« July 2008 | Main | October 2008 »

September 2008 Archives

September 4, 2008

How to build your own geographical based search engine

Our goal: provide to our website users the possibility to find all items (cinemas, restaurants, hotels...) within a defined range of their current locations, sorting results upon distance from them.

What we need: a database containing the latitude and longitude of the items, an interface to allow users to enter their current location (it can be a raw form or an interactive map, as you prefer), various software depending on your next choice.

Now we have at least 2 ways to reach our goal:

- Sql query:
it's the easier method, we already have data in our DB, we need only to execute a relatively simple query with a sub-query. Let's see an example in detail:

SELECT item_name, SQRT(POW((@user_lat - lat) * 111319.5 * COS(RADIANS(@user_lng)),2) + POW((@user_lng - lng)*110946.3,2)) as distance
from ( select item_name, lat, lng
     from items
     where lat >= (@user_lat - @range_degrees/2)
     and lat <= (@user_lat + @range_degrees/2)
     and lng >= (@user_lng - @range_degrees/2)
     and lng <= (@user_lng + @range_degrees/2)
) as boundary
WHERE distance < @range_meters
ORDER by distance;

Using this formula distance is given in meters, and you need to convert user choosen range in meters and degrees. Values 111319.5 and 110946.3 are based on this information.

Patrick O'Leary in his article on GIS based search use an Euclidian formula,I don't know if it's similar or it returns distance in miles etc., I haven't tried it so pay attention when you use his or my formula, do some testing!

- Lucene:
Apache Lucene is a high-performance, full-featured text search engine library written entirely in Java.
Local Lucene is an extension of Lucene providing an implementation of geographical searching. Another similar implementation is GeoLucene but it's still an earlier alpha and his developer is unable to work on this project. Both these software are faster on geographic queries than the unmodified Lucene and for sure faster than Zend_Search_Lucene too.
If you can use Java I recommend to choose Local Lucene, in his whitepaper pjaol shows a comparison beetween Mysql, Lucene and LocalLucene. Instead if you want to use the search capabilities of Lucene in PHP, you can use Solr and, in example, a client like this SolPHP or obtain a JSON response from the server. In this case you can use LocalSolr that is a porting of the LocalLucene library onto the Solr search server.
On GISSearch you can find all information needed to easily build your fast, scalable and reliable geographical search engine.

I hope it will be helpful to you and to your users.

September 12, 2008

Monitoring the connection against TCP/IP socket endpoints in AIR using JavaScript

Adobe AIR gives you the ability to use socket connections for push-model connectivity. For a this application is crucial to check and monitor the the connection against TCP/IP socket endpoints. The AIR service monitor framework can be used for this purposes.

In JavaScript, the operations to check and monitor the connection against TCP/IP socket endpoints use the SocketMonitor that is a subclass of the ServiceMonitor class.

The service monitor framework is external to the standard AIR APIs so that the SocketMonitor can be instanced only after having imported the service monitor framework.
In order to import the service framework, the servicemonitor.swf file needs to be imported with a script tag in the page:

<!-- Include service monitor framework -->
<script src="frameworks/servicemonitor.swf" type="application/x-shockwave-flash" />

The following code uses the SocketMonitor to test and monitor if the network state changes against a given socket endpoint using HTML and JavaScript. If the test has a positive outcome we carry out the connection to the socket server with the nsIServerSocket interface of Mozilla.

The nsIServerSocket interface provides a way to connect to a server socket. It is implemented by this component: @mozilla.org/network/server-socket;1.
This interface is intended to be used as an instance using the following JavaScript syntax:

var myIstance = Components.classes["@mozilla.org/network/server-socket;1"].createInstance(Components.interfaces.nsIServerSocket);

In this example I will use this component and its methods to create a socket server connection.
This is the full HTML file with the service monitor APIs invoked by JavaScript:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>

<!-- Include service monitor framework -->
<script src="frameworks/servicemonitor.swf" type="application/x-shockwave-flash" />

<script type="text/javascript" src="frameworks/AIRAliases.js" />

<script type="text/javascript" src="frameworks/AIRIntrospector.js" />

<script type="text/javascript">

var xmlhttp = newXMLHttpRequest();
var socketConn = null;
var checkSocket = null;
var host = 'localhost';
var port = 25;

function checkConn()
{
checkSocket = new air.SocketMonitor( host, port );
checkSocket.addEventListener(air.StatusEvent.STATUS, announceStatus);
checkSocket.start();
}

function announceStatus(e)
{

document.getElementById("resultDiv").innerText = HTTPMonitor.available;

if (HTTPMonitor.available)
{
socketConn = Components.classes["@mozilla.org/network/server-socket;1"]
.createInstance(Components.interfaces.nsIServerSocket);

socketConn.init(25,false,-1);
socketConn.asyncListen(listener);

} else {
document.getElementById("resultDiv").innerText = 'Can’t connect to the rss feed. The connection is unavailable';
}
}

var listener =
{
onSocketAccepted : function(socketConn, transport)
{
var stream = transport.openOutputStream(0,0,0);
stream.write("OK",2);
stream.close();
},

onStopListening : function(socketConn, status){}
};


</script>

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Monitoring the Connection to a Specific Port on a Server (JavaScript)</title>
</head>

<body onload="checkConn()">

<div id="resultDiv">Checking .... </div>

</body>
</html>

The SocketMonitor class accepts two parameters in the constructor, the host and the port.
These two parameters are declared in the global variables in the script block and then used in the checkConn() function, invoked on the the onload event of the body.

The announceStatus event listener is created, and inside it we check the availability of the socket server. If the result is positive, and therefore the available property returns true, the nsIServerSocket instance of the interface is created with the createInstance()method.

To launch the server socket connection we use the init() method to initiate the connection and we specify the following three topics:

port: specifies the port to listen to

loopbackOnly: indicates whether connections are allowed from any machine or just the same machine

backLog: specifies the length of the queue of incoming connections

Finally, a listener object is passed to the asyncListen method to start the socket listening for connections.

September 19, 2008

Extending the ComboBox Flex component to support multiselection

Working in a new dashboard Flex project, I've faced with the need to implement a multi selection feature on a ComboBox control. My goal was to extend the ComboBox component so that the selectedItems and selectedIndexes properties return the selected item contained in the dataprovider and the indices.
And here's how to make it happens.

Implementing this feature is very simple because the ComboBox is a subclass of the ListBase class that works as a dropdown to show and select items. And from the ListBase class it inherits the multiselection property. So all we have to do is to set the allowMultipleSelection property to true:

dropdown.allowMultipleSelection = true;

Multiselection works when the user presses the CTRL or CMD button on the keyboard to select more than one item. So we need to set to true the value of allowMultipleSelection property each time this button is pressed. This can be done by overridding the keyUpHandler and the keyDownHandler events. The event handlers have to:

1) Set the global variable ctrlKey.
2) Set the allowMultipleSelection property of the dropdown List.
2) When ctrl is up close the dropdown and dispatch the change event.

Remember to define the ctrlKey as global property of the combobox so that every functions can be accessed:

public class ComboBoxs extends ComboBox

{
private var ctrlKey:Boolean = false;

Let see how to do this:

override protected function keyDownHandler(event:KeyboardEvent) : void

{
super.keyDownHandler( event );

ctrlKey = event.ctrlKey;

if ( ctrlKey )
dropdown.allowMultipleSelection = true;

}

override protected function keyUpHandler(event:KeyboardEvent) : void

{
super.keyUpHandler( event );

ctrlKey = event.ctrlKey;


if ( !ctrlKey )
{
close();
var changeEvent:ListEvent = new ListEvent( ListEvent.CHANGE )

dispatchEvent( changeEvent );
}
}

Now we have a full ComboBox Flex control able to receive multiselection but when we click on an item the dropDown menu closes.We need to stop the closure of the ComboBox control if the Ctrl key pressed.
To do this we override the close() method:

override public function close(trigger:Event=null) : void

{
if ( !ctrlKey )
super.close( trigger );

}

Finally we can expose the selectedItems and selectedIndices property of the ComboBox and set them to bindable when the change event is dispatched by the keyUpHandler .
We need to check with an if() conditional statement if the dropdown (the istance name of the ListBase class) is not null before getting its selectedItems property:

public function set selectedItems( value:Array ) : void

{
if ( dropdown )
dropdown.selectedItems = value;

}

[Bindable("change")]
public function get selectedItems( ) : Array

{
if ( dropdown )
return dropdown.selectedItems;

else
return null;
}

public function set selectedIndices( value:Array ) : void

{
if ( dropdown )
dropdown.selectedIndices = value;

}

[Bindable("change")]
public function get selectedIndices( ) : Array

{
if ( dropdown )
return dropdown.selectedIndices;

else
return null;
}

It's all done! Now you have a fully multi selectable combo box.
Here you can see the full class code:

package
{
import flash.events.Event;
import flash.events.KeyboardEvent;


import mx.controls.ComboBox;
import mx.events.FlexEvent;
import mx.events.ListEvent;

public class ComboBoxs extends ComboBox

{
private var ctrlKey:Boolean = false;

public function ComboBoxs()

{
super();
}

override public function close(trigger:Event=null) : void

{
if ( !ctrlKey )
super.close( trigger );

}

override protected function keyDownHandler(event:KeyboardEvent) : void

{
super.keyDownHandler( event );

ctrlKey = event.ctrlKey;


if ( ctrlKey )
dropdown.allowMultipleSelection = true;

}

override protected function keyUpHandler(event:KeyboardEvent) : void

{
super.keyUpHandler( event );

ctrlKey = event.ctrlKey;


if ( !ctrlKey )
{
close();
var changeEvent:ListEvent = new ListEvent( ListEvent.CHANGE )

dispatchEvent( changeEvent );
}
}

public function set selectedItems( value:Array ) : void

{
if ( dropdown )
dropdown.selectedItems = value;

}

[Bindable("change")]
public function get selectedItems( ) : Array

{
if ( dropdown )
return dropdown.selectedItems;

else
return null;
}

public function set selectedIndices( value:Array ) : void

{
if ( dropdown )
dropdown.selectedIndices = value;

}

[Bindable("change")]
public function get selectedIndices( ) : Array

{
if ( dropdown )
return dropdown.selectedIndices;

else
return null;
}

}
}

About September 2008

This page contains all entries posted to Comtaste Consulting | Enterprise RIA consulting and development in September 2008. They are listed from oldest to newest.

July 2008 is the previous archive.

October 2008 is the next archive.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33