While working on the CMP‘s China Media Map, I had the chance to use MapServer, an Open Source platform for publishing spatial data and interactive mapping applications on the Web.
We start with a need: display big datasets of geo-tagged data in an efficient manner for the Web. What do you do? We have over 4000 data points corresponding to individual news agencies in China. Almost each of these points (containing an address) were geotagged using Google’s geocoding service (method shown in another entry). All these points are modeled in a Postgis-enabled PostgreSQL database. We use Google Maps as our display platform. How can we display the points?
One of the early versions, which I knew wouldn’t work in a production environment, was to generate all points as markers. Of course, when you are in the lowest zoom level, at the country-level (China, here), 4000 points risks crashing any more or less recent and decent computer. The alternative is to give users a preview of those 4000+ points, without creating the marker object. What do you do? You check this video out first:
This was shown at Google I/O 2009, and the part of interest is at about 26:31 into the video. This is where the presenter talks about tiny markers. How does Google do it? They don’t actually go into details in the video.
MapServer is the tool you need to use. One of its many uses is to help you create your own custom layer. As you might know, Google Maps works by feeding you 256x256px squares of their map data. These tiles are generated by Google’s in-house map tiles server, which gives the following:
http://mt0.google.com/vt/lyrs=m@124&hl=en&x=836&y=446&z=10&s=Ga
But it is possible to produce your own, with data coming from your own spatial database. Google has an outline of how it’s possible to integrate these easily with their version 3 of the Google Maps API (still in Labs).
You may use MapServer, which has binaries available the major platforms (Windows, Mac, Linux). I use Linux, the Ubuntu distro, so all I had to do was set up the UbuntuGIS Personal Package Archive (PPA) in Unstable to get the latest version of all the GIS software you need.
Use a configuration file such as the one I have: news.map
MAP DEBUG 5 CONFIG "MS_ERRORFILE" "/home/csam/geo/mapserver/error.log" FONTSET "/home/csam/geo/mapserver/fontset.txt" IMAGETYPE PNG #EXTENT 105 15 132 54 EXTENT -40.900557 -99.293024 68.194131 174.885971 #EXTENT -141.018073 41.676949 -52.582296 89.999427 SIZE 256 256 IMAGECOLOR 255 255 255 TRANSPARENT ON OUTPUTFORMAT NAME png DRIVER "GD/PNG" MIMETYPE "image/png" IMAGEMODE RGB EXTENSION "png" FORMATOPTION "INTERLACE=OFF" END PROJECTION "init=epsg:4326" END WEB METADATA WMS_SRS "EPSG:4326 EPSG:900913" END END LAYER NAME news_overview CONNECTIONTYPE POSTGIS CONNECTION "YOUR_OWN_CONNECTION_STRING" DATA "point FROM (SELECT g.gid, g.point, na.name AS placename FROM google_geocoding AS g LEFT JOIN news_agencies AS na ON g.query = lower(na.address) WHERE na.new_id IS NOT NULL UNION SELECT g.gid, g.point, na.name AS placename FROM google_geocoding AS g LEFT JOIN news_agencies AS na ON g.query = lower(na.name) WHERE na.address IS NULL AND na.new_id IS NOT NULL) AS subquery USING UNIQUE gid USING srid=4326 " STATUS ON TYPE POINT CLASS NAME "Points" STYLE SIZE 3 COLOR 255 0 0 END END END LAYER NAME news CONNECTIONTYPE POSTGIS CONNECTION "YOUR_OWN_CONNECTION_STRING" DATA "point FROM (SELECT g.gid, g.point, na.name AS placename FROM google_geocoding AS g LEFT JOIN news_agencies AS na ON g.query = lower(na.address) WHERE na.new_id IS NOT NULL UNION SELECT g.gid, g.point, na.name AS placename FROM google_geocoding AS g LEFT JOIN news_agencies AS na ON g.query = lower(na.name) WHERE na.address IS NULL AND na.new_id IS NOT NULL) AS subquery USING UNIQUE gid USING srid=4326 " STATUS ON TYPE ANNOTATION CLASS NAME "pimple" STYLE SYMBOL "pimple" SIZE 10 COLOR 0 0 0 END LABEL PARTIALS FALSE FORCE TRUE END TEXT ' ' END END SYMBOL NAME 'pimple' TYPE PIXMAP IMAGE "google-pimple.png" TRANSPARENT 0 END LAYER NAME labels CONNECTIONTYPE POSTGIS CONNECTION "YOUR_OWN_CONNECTION_STRING" DATA "point FROM (SELECT g.gid, g.point, ST_AsText(g.point) AS labl FROM google_geocoding AS g LEFT JOIN news_agencies AS na ON g.query = lower(na.address) WHERE na.new_id IS NOT NULL ) AS subquery USING UNIQUE gid " STATUS ON TYPE ANNOTATION MAXSCALE 100000000000 LABELITEM labl CLASS LABEL ANGLE auto SIZE 10 COLOR 192 0 0 TYPE truetype FONT arial END END METADATA WMS_SRS "EPSG:4326 EPSG:900913" END END END
Point to the mapserv CGI with the appropriate arguments. map is the path to your mapscript configuration file, and mode is tile for this purpose, and tilemode will be gmap for Google Maps (could be Bing Maps and OpenStreetMap too).
This is a link to a tile on the China Media Map:
http://jmsc.no-ip.org/cgi-bin/mapserv?map=/home/csam/geo/mapserver/news.map&layers=news&mode=tile&tilemode=gmap&tile=3+1+2
Both the MapServer and PostGIS documentation sites give you examples of how to write the configuration file. The open source geospatial consortium also has a page for showing you what PostGIS is, and how to use MapServer with it for the Web.
Very nice maps.
Curious what font you used.
I’m trying to get both english and chinese characters to work like in your screenshot; and seem to always having trouble with one of the two.
I think it was just Free Sans!