Empress
Technical News -  March 2010
      Interfacing Google Maps with Empress
Spatial Technology
BirdWatching
Location Intelligent Application
 
Introduction
In the old days, a Geographical Information System (GIS) was
the way to provide mapping capabilities integrated with user data. GIS
applications would create interactive spatial queries, analyze spatial
information, manage spatial information and present the results.
Because of the
specialized knowledge involved, the GIS vendor would usually create
those
applications.
Empress Software Inc (ESI) has
collaborated in the past with NOAA and
GIS vendors such as ESRI and Mapinfo to help them provide GIS
applications that
utilize database technology. In those cases, an Empress database was
used as a
storage mechanism for data including geographic information.
In the recent times, the new kids
on the block such as Google,
Microsoft and Yahoo, provide mapping services to end users. As a
result,
building location intelligent applications has become much easier.
In addition,
integrating a geographical component into business processes and tools
is one
of the key enabling technologies for business innovation in coming
years.
The two essential parts of a
typical location intelligent application
are:
- Mapping Service
- Spatial Database
In this technical note we will use a BirdWatching
application to describe how to use the two technologies together to
make a
location intelligent application tick.
Interfacing Google
Maps with Empress Spatial Technology – BirdWatching Application
Around the world, bird watching has become a very
popular
activity. Bird watchers collect records of their observations and share
observation information with others. The bird observation data usually
includes
the name of birds spotted, geo location, time of sightings, the name of
observer(s), etc.  The bird observation
data is accumulated in various formats, such as spreadsheets, text
files and
relational databases. Bird watchers have logged millions of bird
observation events
and continue to log more.
Geo-location is a very important aspect of a bird
observation. It requires a database that can handle huge amounts of
data, and
provide optimized spatial searches.
The BirdWatching Application has been developed
using Empress
Database and Google Maps API to allow users to make queries of observed
bird
data based on geo-locations. It allows users to view and explore bird
data
using a browser based interactive map on the Internet.
Empress Database uses highly efficient R* tree
index for
fast execution of geo-location based queries. Empress Database’s
flexible API
makes it easy to glue Empress database access code with Google Maps API
to
quickly build visual web applications.
In this technical note, we discuss the
implementation of the
BirdWatching application that integrates geo-location data and a
spatial search
from Empress Database with the Google Maps API.
First, the application allows bird lovers to
search global
locations for bird observation events and see the results on Google
Maps.
Figure 1: Querying Birds Observations by Location
In Figure 1, an user can search bird observation
events by
specifying an address and a radius. The address can be a street
address, a city
name, a park name or any addresses acceptable to Google Maps. The query
result
is displayed by showing each bird observation on the map at the
location where
the event took place. To get the observation details, a user can click
on the
place marks and the names of birds spotted at the location will be
displayed
along with other information.
The application also enables users to report bird
observation events by clicking on the map to specify the location of
the event
and provide details.
Figure 2: Reporting a Bird Observation
Figure 2 shows how users submit a bird
observation. When the
user saves the observation, the data is stored in the Empress database
and
becomes instantly available to other users around the world.
Implementation of the BirdWatching Application
We will look at the BirdWatching application
starting with
its Architecture and then moving on to Database Schema, Empress
Database CGI
Program, Client Side Programming and Conclusion.
BirdWatching Application Architecture
Figure 3: Architecture of the BirdWatching
Application
In the Figure 3, the application
includes server side and client side components.
The server side consists of an
Empress database providing storage and indexing of the bird observation
data
and a HTTP server that invokes a CGI program upon users’ requests. The
CGI
program processes users’ requests, communicates with the Empress
database and
returns the results back to client through the HTTP server.
The client side is composed of
HTML and JavaScript running within a web browser. It uses JavaScript
Ajax
(asynchronous JavaScript and XML) to communicate with the server side
CGI
program to submit queries and get results back packaged as a JSON
(JavaScript
Object Notation) object.
The client side also calls Google
Maps API with the application data to display observation data on the
map. The
actual map images and map control functions are from Google Maps
servers. The
JavaScript code is also used for interacting with users.
 
The Database Schema
The bird observation data of this application is
stored in
two Empress Database tables. The first table, bw_events, contains
general information about bird observation
events, such as event id, event time, event longitude and latitude.
 
***  Table: bw_events  ***
        Attributes:
 
        event_id                                       
 
 
 
 
 
character(8)
 
 
 
    event_lat                                               
double precision
 
 
 
    event_lng                                             
double precision
 
 
 
    event_time                                         
timestamp(0)
 
 
 
    count_type                                         
character(4)
 
 
 
    effort_hrs                               
 
 
 
 
 
 
 
float(24)
 
 
 
    distance                                               
float(24)
 
 
 
    effort_area_ha                           
float(24)
 
 
 
    observer_id                                   
character(12)
 
        observers_no                             
integer
 
        Indices:        RSTARTREE
geoindex ON (event_lat,
event_lng)
The attributes event_lat and event_lng
represent the exact
geographic location of an event. Their values are used by Google Maps
API to
locate the observation event on the map. 
The R* tree index (spatial index) defined on the two attributes
is used
to speed up spatial queries.
For each observation event, there might be more
than one
bird observed out of thousands bird species. We need another table to
store
bird names associated with each event. The table, bw_bird
is defined as follows:
 
      ***  Table: bw_birds  ***
 
 
 
  Attributes:
 
        event_id                                                   
character(8)
 
        bird_name                                           
character(32)
 
 
      bird_no                                                     
character(4)
 
     
 
 
 
  Indices:        NORMAL(2, 15) BTREE indx1 ON (event_id)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
     
 
 
NORMAL(2, 15) BTREE indx2 ON (bird name)
The two tables are linked to each other by the event_id attribute with a one-to-many
relationship.
 
                                                                                                     
Figure 4. The Relationship Between bw_events and bw_birds
 
The Empress Database CGI Program
The Empress Database CGI program uses CGI protocol
to
receive Ajax HTTP request from client side, queries the database using
Empress
C/C++ MR routines (API calls) and composes Ajax HTTP responses to the
client
side with the result of a query. It takes following steps to complete
the
search of all bird observation events in a certain area.
- It parses HTTP requests from the
client side to get the latitude/longitude values of the geographic
center of the area and the radius of the area.
- It calls Empress Database Spatial
Search function    ms_rstree_point_search_in_circle()
with the latitude, the longitude and the radius to find a
list of all event records that are contained in the specified circle
area.
 
- It uses the event record list from the
previous step to retrieve observation data from bw_events and bw_birds
tables for each event in the area.
 
- It assembles the resulting bird
observation event data into a JSON literal string and sends it back to
the client side as in an HTTP response.    Due to
its simplicity, JSON is natively supported in all major web browsers
and widely utilized in web applications.
 
The following is the part of the program source
code:
 
void
search_birds ()
{
 
 
 
 
 
void* mr_event
 
 
 
 
 
void* mrr_event
 
 
 
 
 
void* id_attr
 
 
 
 
 
void*          
lat_attr
 
 
 
 
 
void* lng_attr
 
 
 
 
 
void* time_attr
         
 
 
void*   
observer_id
 
 
 
 
 
void* mr_birds
 
 
 
 
 
void* mrr_birds
 
 
 
 
 
void* bid_attr
 
 
 
 
 
void* bname_attr
 
 
 
 
 
void* bnum_attr
 
 
 
 
 
void*          
qual
 
 
 
 
 
void* qual2
 
 
 
 
 
void* q
         
 
 
void*   
retrieve_events
 
 
 
 
 
 
 
void*   
retrieve_birds
 
 
 
 
 
void* rshandle
 
 
 
 
 
 
 
long*  
rec_list
 
 
 
 
 
double         
circle[3]
 
 
 
 
 
int  
i
 
 
 
msinit ()
 
 
 
 
 
mr_event = mropen(DATABASE, " bw_events" , 'r')
 
 
 
 
 
mrr_event = mrmkrec (mr_event)
 
 
 
 
 
id_attr = mrngeta (mr_event, " event_id" )
 
 
 
 
 
lat_attr = mrngeta (mr_event, " event_lat" )
 
 
 
 
 
lng_attr = mrngeta (mr_event, " event_lng" )
 
 
 
 
 
time_attr = mrngeta (mr_event, event_time"
 
 
 
 
 
mr_birds = mropen(DATABASE, " bw_birds" , 'r')
 
 
 
 
 
mrr_birds = mrmkrec(mr_birds)
 
 
 
 
 
bid_attr = mrngeta (mr_birds, " event_id" )
 
 
 
 
 
bname_attr = mrngeta (mr_birds, bird_name"
 
 
 
 
 
bnum_attr = mrngeta (mr_birds, bird_no" )
 
 
 
 
 
rshandle = ms_rstree_open (mr_event,
lat_attr, lng_attr, 0)
 
 
 
if (rshandle
== 0)
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fprintf (stderr, " cannot
open rstree index \n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
goto done
 
 
 
 
 
}
 
 
 
 
 
circle[0] = lat
 
 
 
 
 
circle[1] = lng
 
 
 
 
 
circle[2] = radius / 111
 
 
 
 
 
fprintf (stderr, " Searching
event in (%f, %f, %f). \n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
circle[0], circle[1],
circle[2])
 
 
 
 
 
rec_list =
ms_rstree_point_search_in_circle (rshandle, circle)
 
 
 
 
 
printf (" {\" events\" :\n"
 
 
 
 
 
printf (" [\n" )
 
 
 
 
 
if (rec_list
== 0)
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fprintf (stderr, " No
event found in (%f, %f, %f). \n" ,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
circle[0],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
circle[1],
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
circle[2])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
goto done
 
 
 
 
 
}
 
 
 
 
 
qual = mrqlst (mr_event, rec_list)
 
 
 
 
 
if (! qual)
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
printf (" %s\n" , mrerrmsg())
 
 
 
 
 
 
 
 
 
 
 
return
 
 
 
 
 
}
 
 
 
retrieve_events = mrgetbegin (qual,
mrr_event, (void 0)
 
 
 
 
 
i = 0
 
 
 
 
 
while (mrget
(retrieve_events) == 1)
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
char* eid
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
double*       
lat
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
double*       
lng
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
int j
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if (i > 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" ,\n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" {\n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
eid = mrgetvs (mrr_event,
id_attr)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
qual2 = mrqseq (bid_attr,
eid)
 
 
 
 
 
 
 
 
 
 
 
          printf
("
\"
eid\"
:
\"
%s\"
,\n"
, eid)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" \" lat\" :
\"
%f\"
,\n"
,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
*(double*)mrgeti
(mrr_event, lat_attr))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" \" lng\" :
\"
%f\"
,\n"
,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
*(double*)mrgeti
(mrr_event, lng_attr))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" \" time\" :
\"
%s\"
,\n"
,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mrgetvs (mrr_event,
time_attr))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
retrieve_birds =
mrgetbegin(qual2, mrr_birds,           
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if (!
retrieve_birds)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" %s\n" , mrerrmsg())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
break
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
j = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
while
(mrget(retrieve_birds) == 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if (j > 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" ,\n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
else if (j == 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" \" birds\" :
[\n"
)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
          printf
("
{\n"
)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" \" name\" :
\"
%s\"
,\n"
,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mrgetvs
(mrr_birds, bname_attr))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" \" number\" :
\"
%s\"
\n"
,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mrgetvs
(mrr_birds, bnum_attr))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" }\n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
j++
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
if (j > 0)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" ]\n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
printf (" }\n" )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
mrgetend(retrieve_birds)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
i++
 
 
 
 
 
}
 
 
 
 
 
mrgetend (retrieve_events)
 
 
 
 
 
fprintf (stderr, " %d
events found\n" i)
 
 
 
 
 
ms_rstree_list_free (rec_list)
done:
 
 
 
 
 
printf (" ]\n" )
 
 
 
 
 
printf (" }\n" )
 
 
 
 
 
mrfrrec (mrr_event)
 
 
 
 
 
mrfrrec (mrr_birds)
 
 
 
 
 
mrclose (mr_event)
 
 
 
 
 
mrclose (mrr_event)
 
 
 
 
 
ms_rstree_close (rshandle)
 
 
 
 
 
msend ()
}
 
An HTTP request from the client could look like:
http://localhost/cgi-bin/birdwatch/searchdb?lat=25.7742657& lng=-80.1936589& radius=6.
It asks for finding all observation events inside
the circle
with the center of 25.7742657, -80.1936589, (Miami FL)
and a radius of 6 kilometers.
The following is the body of an HTTP response
generated by
the CGI program. It shows the bird observation event happened at
(25.736817,
-80.156517) and two kinds of birds were spotted at the location: macroura and
Cardinalis cardinalis.
  {" events" :
 
 
 
[   
 
 
 
      {       
 
 
 
      " eid" : " S3646552" ,
 
 
 
 
    " lat" : " 25.736817" ,
 
 
 
 
    " lng" : " -80.156517" ,
 
 
 
 
    " time" : " 2008-03-01 12:45:00" ,
 
 
 
 
    " birds" : [
 
 
 
 
 
 
 
{
 
 
 
 
 
 
 
      " name" : " Zenaida_macroura" ,
 
 
 
 
 
 
 
 
    " number" : " 22"
 
 
 
 
 
 
 
},
 
 
 
 
 
 
 
{               
 
 
 
            " name" : " Cardinalis_cardinalis" ,
 
 
 
 
 
 
 
 
    " number" : " 2"
 
 
 
 
 
 
}
 
 
 
 
]
 
 
}
 
]
} 
Client Side Programming
Client side programming is a combination of HTML
and
JavaScript code running inside a web browser, (Chrome, Firefox, Safari
and
IE8).
The client side uses Ajax,
JSON and Google Maps API to do the following tasks:
- When a user types in an address on the
web page, it uses Ajax calls to send the address to the Google Maps geo-coding service to
search for the address and translate it into associated geographic
coordinates as latitude and longitude.
- It then sends the geographic
coordinates and the user inputted radius value to the CGI program on
the server side as HTTP requests. For example,
                     
http://localhost/cgi-bin/birdwatch/searchdb?lat=25.7742657&
lng=-80.1936589&
radius=6
- Upon receiving the HTTP response from
the server side, it parses the data embedded in the response into a
JavaScript JSON object, which represents all events in the search area.
It then retrieves geographic coordinates of every event from the object
and passes them to the Google Maps API to show each bird observation
event.
- Responds to users’ interaction. When a
user clicks on a mark on the map, it responds by displaying details of
the event in a pop-up window on the map. When the user zooms in and out
of the map, it adjusts the number of events to be displayed on the map
to reduce visual clutters.
Parts of the client side code is as follows:
  // load map
function load() {
 
 
 
 
 
if
(GBrowserIsCompatible()) {
 
 
 
 
 
 
 
geocoder = new
GClientGeocoder()
 
 
 
 
 
 
 
map = new
GMap2(document.getElementById('map'))
 
 
 
 
 
 
 
map.addControl(
GLargeMapControl())
 
 
 
 
 
 
 
map.addControl(
GMapTypeControl())
 
 
 
 
 
 
 
map.setCenter(new
GLatLng(40, -100), 4)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
var icon = new
GIcon(G_DEFAULT_ICON)
 
 
 
 
      icon.image = " http://chart.apis.google.com/chart?cht=mm& chs=24x32& chco=FFFFFF,008CFF,000000& ext=.png"
 
 
 
 
 
}
 
 
 
}
function
searchLocations() {
 
 
 
 
var address =
document.getElementById('addressInput').value
 
 
 
 
geocoder.getLatLng(address, function(latlng) {
 
 
 
 
 
 
if (!latlng)
{
 
 
 
 
 
 
 
 
alert(address
+ '
not found')
 
 
 
 
 
 
} else {
 
 
 
 
 
 
 
 
searchLocationsNear(latlng)
 
 
 
 
 
 
}
 
 
 
 
})
 
 
}
 
 
function
searchLocationsNear(center) {
 
 
 
 
var radius =
document.getElementById('radiusSelect').value
 
 
 
 
var searchUrl
= '/cgi-bin/birdwatch/searchdb2?lat=' +
center.lat() + '& lng=' + center.lng() +
'&
radius=' + radius + bn=xxx'
 
 
 
 
GDownloadUrl(searchUrl, function(data) {
 
 
 
 
 
 
var jsondata =
eval('(' + data + ')'
 
 
 
 
 
 
var markers =
jsondata.markers
 
 
 
 
 
 
map.clearOverlays()
 
 
 
 
 
    if
(markerCluster != null)
 
 
 
 
 
                   
markerCluster.clearMarkers()
 
 
 
 
 
 
var sidebar =
document.getElementById('sidebar')
 
 
 
 
 
 
sidebar.innerHTML
= ''
 
 
 
 
 
 
if
(markers.length == 0) {
 
 
 
 
 
 
 
 
sidebar.innerHTML =
results found.'
 
 
 
 
 
 
 
 
 
 
 
 
 
map.setCenter(new
GLatLng(center.lat(), center.lng()), 11)
 
 
 
 
 
 
}
 
 
 
 
 
 
var bounds = new
GLatLngBounds()
 
 
 
 
 
    var gmarkers =
[]
 
 
 
 
 
 
for (var i = 0 i
<
markers.length i++) {
 
 
 
 
 
 
 
 
var name =
markers[i].eid
 
 
 
 
 
 
 
 
var point = new
GLatLng(markers[i].lat, markers[i].lng)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
  var bds =
markers[i].birds
 
 
 
 
 
 
 
 
 
 
 
  if (! bds)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
var mhtml
 
 
 
 
 
 
 
 
 
 
 
  mhtml = < ul> "
 
 
 
 
 
 
 
 
for (var j = 0 j
<
bds.length j ++) {
 
 
 
 
 
 
 
 
 
 
 
 
mhtml = mhtml + < li> " + bds[j].name + " ("
bds[j].number + )" + " < /ui> "    
 
 
 
 
 
 
 
 
}
 
 
 
 
 
 
 
 
mhtml =
mhtml + " < /ul> "
 
 
 
 
 
 
 
 
var marker =
createMarker(point, name, mhtml)
 
 
 
 
 
 
 
 
 
 
 
  gmarkers.push(marker)
 
 
 
 
 
 
 
 
//
map.addOverlay(marker)
 
 
 
 
 
 
 
 
var sidebarEntry
= createSidebarEntry(marker, name, '', '')
 
 
 
 
 
 
 
 
sidebar.appendChild(sidebarEntry)
 
 
 
 
 
 
 
 
//
bounds.extend(point)
 
 
 
 
 
 
}
 
 
 
 
 
   
 
 
 
 
 
 
 
 
 
 
 
var gct =
createMarker(new
GLatLng(center.lat(),
center.lng()),
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
'Search Center: (' + center.lat() +
',
' +
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
center.lng() + , ''
 
 
 
 
 
 
 
 
 
 
 
map.addOverlay(gct)
 
 
 
 
 
 
 
 
 
 
 
markerCluster =
MarkerClusterer(map, gmarkers,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
{maxZoom: 12, gridSize: 30})
 
 
 
 
 
 
 
 
 
 
 
 
map.setCenter(new
GLatLng(center.lat(), center.lng()))
 
 
 
 
})
 
 
}
 
function
createMarker(point, name, birds) {
 
 
 
 
 
var marker = new
GMarker(point)
 
 
 
 
 
var html = '< b> ' + name + br/> ' + 'Birds
Observered: ' + /b>
<
br/>
'
 
 
 
 
 
 
 
 
 
 
 
+ '< div
style="
overflow: auto height:100px" > ' +
birds + '< /div> '
 
 
 
 
 
GEvent.addListener(marker, 'click', function() {
 
            marker.openInfoWindowHtml(html)
 
 
 
 
 
})
 
 
 
 
 
return marker
}
 
Instead of Conclusion
The BirdWatching application shows how Empress
Spatial index
search functionality is integrated with Google Maps API and other web
technologies. Using this technology stack, application developers can
build
high performance, geographical data-driven applications with a top
class user
experience.
Google Maps API
&
Empress Spatial Technology are essential
components for making location intelligent applications do what they
should.
 
Empress Software Inc.
www.empress.com
 
|