Lazily Creating GMaps Marker Sets Using PHP and GD
Google Maps marks locations with marker icons - I'm sure you're all familiar with the default red balloon-shaped icons at the Google Maps site. If you are using the Google Maps API to incorporate maps into your web applications, it's quite possible that you will want or need to use custom marker icons. Some of the harder use cases are the ones in which you need numbered or lettered icons in a range of different colors.
For example, let's say you have a Drupal 6 website in which you are displaying nodes by their location, using some version of the capabilities offered by the Views, GMap, and GMap Location modules. Your display page shows a GMap view and a paged list of nodes of various different content types: you want the marker icons displayed on the map to be numbered to correspond to the nodes in the paged list. Additionally, the markers should be displayed in different colors that correspond to the different content types.
Now, you might have fifty or a hundred items in that paged list in the worse case. If you have three different content types (say Food, Bars, and Friends), you might be looking at having to have 300 or more distinct marker icons available for use. Clearly, no-one wants to be on the hook for producing that many distinct icons by hand; what are the alternatives?
- Find existing free online marker icon sets
- Use the Charts API to create marker icons on the fly
- Take an existing marker set and recolorize it
Find Existing Markers
There is a good list of freely available numbered and lettered icon sets at mapki.com, but of that list only a couple of sets are attractive, and only one set is both large and attractive.
The Charts API Method
By using an open utility such as MapIconMaker, you can specify markers on the fly. You can either do this in your web application, making a call to the Charts API for every displayed icon, or for preference run up some code beforehand to programatically generate the marker sets you need.
The PHP GD Recolorization Method
The GD library for PHP allows for fairly easy and painless operations on images. So you can take an existing numbered marker set and clone it into new sets with altered colors - or take an existing blank marker image and produce a set from it by adding numbers to it.
A How-To For the Drupal and GMap Example
Since I'm in a PHP mood, I'll demonstrate the lazy version of the last of these three options: find an existing numbered marker set, and from it clone new sets with different colors. For the base set I picked the 0-99 numbered markers from Prime Suspect. Download those markers and unzip them into a directory. Now we write a short PHP script to generate two more sets:
$source_dir = "/path/to/marker/dir"; $destination_dir = "/path/for/new/sets"; // Open the marker set directory and loop through the image files // contained within it. if( $dh = opendir($source_dir) ) { while( false !== ($filename = readdir($dh)) ) { generate_new_images($filename); } closedir($dh); } function generate_new_images($filename) { global $source_dir, $destination_dir; // create the needed destination directories if they don't exist: $output_dir_1 = $destination_dir . '/rotation1'; $output_dir_2 = $destination_dir . '/rotation2'; if( !is_dir($output_dir_1) ) { mkdir($output_dir_1, 0755, true); } if( !is_dir($output_dir_2) ) { mkdir($output_dir_2, 0755, true); } // load the image: in this case the markers happen to be PNGs. $image = imagecreatefrompng($source_dir . '/' . $filename); // alter the image colors in a fairly simple way and write to file rotateColor($image); imagepng($image, $output_dir_1 . '/' . $filename); // now do that all again to get the third option for rotated colors. rotateColor($image); imagepng($image, $output_dir_2 . '/' . $filename); } /* * Given an image, rotate its color values - red becomes * green, green becomes blue, blue becomes red. */ function rotateColor($image) { // loop through all the pixels in the loaded image for( $y = 0; $y < imagesy($image); $y++ ) { for( $x = 0; $x < imagesx($image); $x++ ) { // obtain comprehensible RGB color space values $rgb = imagecolorat($image, $x, $y); $pixel = imagecolorsforindex($image, $rgb); // now rotate the color values one to the right: // red becomes green, green becomes blue, etc. $pixelcolor = imagecolorallocatealpha( $image, $pixel['blue'], // -> red $pixel['red'], // -> green $pixel['green'], // -> blue $pixel['alpha'] // and the alpha channel stays put ); imagealphablending($image, TRUE); imagesavealpha($image, TRUE); imagesetpixel($image, $x, $y, $pixelcolor); } } }
All this does is rotate the values in the RGB color space: there are other simple combinations that could be produced, such as by swapping red and green, or green and blue, and so forth. If you don't care too greatly about the actual colors needed, then this is a good way of generating new sets that look just as good as the original.
Introducing Numbered Marker Sets to Drupal
The GMap module contains a /markers folder; drop the folders containing your new numbered marker sets into there. You will need to add a description file to each folder. The format for a set of simple numbered marker images is as follows:
[defaults] anchorX = 10 anchorY = 29 infoX = 17 infoY = 6 [my marker set name] name = "my marker set name" sequence = "mymarker1.png,mymarker2.png,mymarker3.png,..."
You do have list every file in the set in order in the comma-separated sequence - that list is omitted here to save space. Then in the Drupal administration, navigate to the GMap settings at /admin/settings/gmap and click the "Regenerate" button to rebuild the cache of marker sets. Then navigate to the GMap Location settings at /admin/settings/gmap_location and scroll down to the Markers per content type section. If, as per my example at the top of this post, your maps contain content types for Food, Bars, and Friends, then choose a different marker set for each.
Now if you clear the caches and go take a look at your map page, you'll see numbered icons showing up in different colors. There is, however, a fly in the ointment: the default behavior of GMap Location is to count markers separately for each new content type that appears on a map. So if your map shows 7 Food nodes, 5 Bar nodes, and 3 Friend nodes, you'll see Food 1-7, Bar 1-5, and Friend 1-3 rather than a continuous numbering of 1-15 through all three types.
Fortunately, this can be fixed though the use of hook_gmap(). You will have to create a new module called "GMap Fixes" and put the following code into it.
/** * Implementation of hook_gmap(). */ function gmap_fixes_gmap($op, &$map) { if( $op == 'pre_theme_map' ) { if( isset($map['markers']) && is_array($map['markers']) ) { foreach( $map['markers'] as $index => &$marker ) { // set the offset into the marker list // to be continuous through the list of nodes $marker['offset'] = $index; } } } }
Enable your new module, and lo and behold, your numbered, multicolored marker icons now work as intended.