Showing posts with label Google Maps API. Show all posts
Showing posts with label Google Maps API. Show all posts

Monday, February 4, 2013

Creating a Custom Pop Up with a Spatial Query


The next hurdle I ran into while creating the GeoLinx application was creating a pop up that would display the attributes for more than one feature in the same spatial location.  Each job post is geocoded to a city because very rarely is a full address included in the post.  So each post is typically located at the centroid of the city (or sometimes a specific place like a military base).  Because of this, the points stack on top of each other.  The basic pop up implemented with the Google Maps API will only get the information for the point on top.  To overcome this I had to create by own code to select all of the points within a radius of the user’s click.



First I created a Fusion Tables layer to display the points on the map.  I did this simply by following the documentation.  I did suppress the default Info Window, otherwise two pop ups would appear when the user clicks on the point.  I also included a SQL query to not show posts older than a specified date or that have expired.  You can find many good examples of JavaScript functions that will get the current data or a past date.  Finally, I created a new Info Window that would display the attributes for the selected postings.  An Info Window is simply the normal pop up you see in most Google Maps applications.

var ftLayer = new google.maps.FusionTablesLayer({
              suppressInfoWindows: true,
              query: {
                    select: 'GeoCode',
                    from: table,
                    where: "PostDate > '" + currentDate +
                        "' AND (ExpireDate > '" + todaysDate + 
                        "' OR ExpireDate = '')"
              }
});
ftLayer.setMap(map);

var infoWindow = new google.maps.InfoWindow();

The next step was to create a listener for click event of the Fusion Tables layer.  This simply tells the application to “listen” for the user to click on a point in the layer and then do something.  Once again I followed the documentation for this.  I then built a query to select the attributes I wanted to display.  I used a spatial query to select the features within a certain distance of the users click.  Next it is essential convert the query to a URL format.  Then I completed the query string by including the rest of the URL path and my key.   Finally, I created a Google Visualization query using the Google Visualization API.

google.maps.event.addListener(ftLayer, 'click', function (event) {
      var query = "SELECT Title, GeoCode, Organization, " + 
                   "PostDate, URL FROM " +
                   table +
                   " WHERE ST_INTERSECTS(GeoCode, CIRCLE(LATLNG"
                   event.latLng + ", 5000)) ORDER BY PostDate DESC";
      query = encodeURIComponent(query);
      query = 'http://www.google.com/fusiontables/gvizdata?tq='
               query + '&key=’ + key;

      var gvizQuery = new google.visualization.Query(query);

Once the query was created, I sent the query to the server to get back the result.  I also had to create some HTML formatting to display the results in a tabular format.  The Info Window will take straight HTML.  I cut back some of the HTML formatting below to reduce the length of this post but you can research tables for HTML if you need to.  Using the Google Visualization API, I looped through each row of the returned query and build each row in the table.  I also had to do some formatting on the dates.  The final steps were to set the position of the pop up to the user’s click, feed the HTML code for the table to it, and the open the info window.

      gvizQuery.send(function (response) {
         var content = ...//HTML here

         var numRows = response.getDataTable().getNumberOfRows();

         for (var i = 0; i < numRows; i++) {
               var title = response.getDataTable().getValue(i, 0);
               var loc = response.getDataTable().getValue(i, 1);
               var org = response.getDataTable().getValue(i, 2);
               var pDate = response.getDataTable().getValue(i, 3);
               var url = response.getDataTable().getValue(i, 4);

               pDate = postDate.toString();
               pDate = postDate.replace(
                     '00:00:00 GMT-0500 (Eastern Standard Time)'
                     '');
               pDate = postDate.substr(3, postDate.length);

               content = content +
                    + title + ...//HTML here
                    + loc + ...//HTML here
                    + org + ...//HTML here
                    + pDate + ...//HTML here
          }

          content = content + ...//HTML here

          infoWindow.setPosition(event.latLng);
          infoWindow.setContent(content);
          infoWindow.open(map);
      });
});

Overall, I had a difficult time putting this together because it uses code from three Google APIs, and I couldn’t find examples doing exactly this.  But I did learn a lot that I would use in other parts of the application.  Just a note: I’m sure there are other and better ways to do this.  Feel free to comment if you have better solutions.  The next part of the project was to add search functionality that would center and zoom the map to the address or zip code that the user specifies.

Friday, January 25, 2013

Using Fusion Tables for GeoLinx

Building the GeoLinx website was my first experience with the Google Maps API. While I have plenty of experience with HTML, I have only used Javascript on a limited basis (most of my experience has been with C# and Python). So this project has been a learning experience for me. I used a lot of the sample code provided by Google and others users. However, I have run into many instances where I could not find samples to meet my needs, so I had to create a solution on my own. I will continue to post the solutions as I come across them so anyone else with the same problem will have a reference.

Getting a basic map displayed was easy by simply following along with the tutorial provided by Google. The first issue I encountered was where to store the data and how would I display it. In this case the data was the location of job postings. I didn’t want to use a spatial database like SQL Server or PostgreSQL at this point because of the time to set this up as well as the problem of where to host this database. So I looked at KML first. While this would meet my needs, maintaining a KML with frequent updates would take quite a bit of work.



Then I discovered Google Fusion Tables. This seemed like the perfect solution for the time being. Fusion Tables are basically a database table stored on Google Drive and can be manipulated like any other document. In addition, Google provides an API that allows you to access and modify these tables with SQL like any other database table. But the most interesting part about Fusion Tables is that you can add a spatial field like any other spatial database. But the most exciting aspect is that this field can not only store latitude and longitude coordinates, but it can also store a string to be geocoded. So for example after entering “Pittsburgh, PA”, Fusion Tables will automatically geocode this string and convert it to the proper coordinates. This method uses the same geocoding service that Google Maps uses, so you can check where the point where be placed by simply typing the string into Google Maps.

The downside of Fusion Tables is that it is still considered experimental so it is lacking many of the useful features of most databases. One lacking feature is the ability to add an auto-populating unique ID field. There are also many useful SQL functions missing. Fusion Tables does allow for basic spatial SQL queries. These functions are also not nearly as robust as most spatial database but they have met my needs so far.

To get started I created a simple table that keeps track of the position title, the location (usually city and state) for geocoding, the city, state, country, organization, date posted, expiration date (if applicable), the class (technician, analyst, developer, etc), and the URL to the posting. Once this table was set up with some data, I simply followed the API reference do display these points on the map. I added a SQL query to only display jobs that have not expired and were posted within in 60 days so the posting are relevant.



The next step was creating a custom popup window that would display the attributes for all of the points in the same location. Check back soon!

Thursday, January 24, 2013

An Introduction to GeoLinx


The GeoLinx project started out as a simple concept - bringing geospatial industry professionals together through the sharing of information.  The idea started in early 2008 when we realized that searching for jobs in the GIS industry was difficult because there were only a few sources dedicated to this specific discipline of career postings.  At that time we started the "The Western Pennsylvania GIS Newsletter" focusing on GIS jobs in the western Pennsylvania area (where we were located at the time).   The newsletter gained quite a following during it’s time.  Unfortunately, due to time constraints the newsletter fell by the wayside.

During this time, the GeoLinx project was envisioned.  We wanted to create a one-stop site where GIS professionals could find information on professional organizations, educational institutions and programs, GIS firms, career opportunities, and GIS events.  Obviously this would be a large undertaking that would take far more resources than we had at the time.

GeoLinx

Development Faction, LLC was formed in March of 2009.  Over the past several years, we have been growing in size and experience.  In the fall of 2012 we decided to revisit the GeoLinx project as a side project.  We would allocate some time to develop the GeoLinx site when it was possible.  We decided that a phased approach was the best method of getting GeoLinx off the ground.  The obvious target seemed to be GIS job postings.  We decided this would be perfect excuse to play with the Google Maps API.

So that is how the GeoLinx website got its start.  The first version allows users search for job posting within a specified radius.  The user can select jobs and is redirected to the original job post.  A GIS approach for searching for GIS jobs seemed like the perfect approach.  We currently update the site daily (usually), and job posting can be located anywhere in the world, however, are mostly centered in North America since this is where we are located and get the most postings.

Since we have launched the first version of the site, we have been pleased with the positive feedback we have been getting, as well as the large volume of traffic to the site.  We plan to continue to improve the site and already have a long list of enhancements and new features planned.  We hope to get more users sending us posts so we don’t have to search for them ourselves.  We are also posting jobs on Twitter daily.  Finally, we will be following up with regular posts on the project and the development of the site as we go, so check back regularly.