Skip to content

MarkHofstetter/GoogleMapsHeatmap

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
t
 
 
www
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

NAME

Geo::Heatmap - generate a density map (aka heatmap) overlay layer for Google Maps

see the www directory in the distro how it works

see the script directory for creating a scale

for a real life example see

http://www.trust-box.at/dev/gm/GoogleMapsHeatmap/www/GoogleMapsHeatmap.html

for Dokumentation see

HOMEPAGE

http://www.trust-box.at/googlemaps-geoheatmap/

REQUIRES

Moose
CHI
Imager

METHODS

tile

tile();

return the tile image in png format

ATTRIBUTES

debug
cache
logfile
return_points
zoom_scale
palette

USAGE

Create a Heatmap layer for GoogleMaps

The HTML part


  <head>
     <meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
     <style type="text/css">
       html { height: 100% }
       body { height: 100%; margin: 0; padding: 0 }
       \#map-canvas { height: 100% }
     </style>
     <script type="text/javascript"
       src="https://maps.googleapis.com/maps/api/js?key=&sensor=true">
     </script>
     <script type="text/javascript">
       var overlayMaps = \[{
         getTileUrl: function(coord, zoom) {
           return "hm.fcgi?tile="+coord.x+"+"+coord.y+"+"+zoom;
         },
 

            tileSize: new google.maps.Size(256, 256),
            isPng: true,
            opacity: 0.4
          }];
    
          function initialize() {
            var mapOptions = {
              center: new google.maps.LatLng(48.2130, 16.375),
              zoom: 9
            };
            var map = new google.maps.Map(document.getElementById("map-canvas"),
                mapOptions);
    
          var overlayMap = new google.maps.ImageMapType(overlayMaps[0]);
          map.overlayMapTypes.setAt(0,overlayMap);
    
          }
          google.maps.event.addDomListener(window, 'load', initialize);
    
       </script>
     </head>
     <body>
       <div id="map-canvas"/>
    </body>
  
  

The (f)cgi part


  \#!/usr/bin/env perl
  

    use strict;
    use FCGI;
    use DBI;
    use CHI;
    use FindBin qw/$Bin/;
    use lib "$Bin/../lib";
    
    use Geo::Heatmap;
    
    #my $cache = CHI->new( driver  => 'Memcached::libmemcached',
    #    servers    => [ "127.0.0.1:11211" ],
    #    namespace  => 'GoogleMapsHeatmap',
    #);
    
    
    my $cache = CHI->new( driver => 'File',
             root_dir => '/tmp/GoogleMapsHeatmap'
         );
    
    
    our $dbh = DBI->connect("dbi:Pg:dbname=gisdb", 'gisdb', 'gisdb', {AutoCommit => 0});
    
    my $request = FCGI::Request();
    
    while ($request->Accept() >= 0) {
      my $env = $request->GetEnvironment();
      my $p = $env->{'QUERY_STRING'};
    
      my ($tile) = ($p =~ /tile=(.+)/);
      $tile =~ s/\+/ /g;
    
      # package needs a CHI Object for caching
      #               a Function Reference to get LatLOng within a Google Tile
      #               maximum number of points per zoom level
    
      my $ghm = Geo::Heatmap->new();
      $ghm->palette('palette.store');
      $ghm->zoom_scale( {
        1 => 298983,
        2 => 177127,
        3 => 104949,
        4 => 90185,
        5 => 70338,
        6 => 37742,
        7 => 28157,
        8 => 12541,
        9 => 3662,
        10 => 1275,
        11 => 417,
        12 => 130,
        13 => 41,
        14 => 18,
        15 => 10,
        16 => 6,
        17 => 2,
        18 => 0,
      } );
    
    sub get_points {
      my $r = shift;
    
      my $sth = $dbh->prepare( qq(select ST_AsEWKT(geom) from geodata
                             where geom &&
                  ST_SetSRID(ST_MakeBox2D(ST_Point($r->{LATN}, $r->{LNGW}),
                                          ST_Point($r->{LATS}, $r->{LNGE})
                            ),4326))
                  );
    
      $sth->execute();
    
      my @p;
      while (my @r = $sth->fetchrow) {
        my ($x, $y) = ($r[0] =~/POINT\((.+?) (.+?)\)/);
        push (@p, [$x ,$y]);
      }
      $sth->finish;
      return \@p;
    }
    
    

You need a color palette (one is included) to encode values to colors, in Storable Format as an arrayref of arrayrefs eg

[50] = [34, 45, 56]

which means that a normalized value of 50 would lead to an RGB color of 34% red , 45% blue, 56% green.

  • zoom_scale

    The maximum number of points for a given google zoom scale. You would be able to extract to values from the denisity log or derive them from your data in some cunning way

  • cache

    You need some caching for the tiles otherwise the map would be quite slow. Use a CHI object with the cache you like

  • return_points

    A function reference which expects a single hashref as a parameter which defines two LAT/LONG points to get all data points within this box:

        $r->{LATN}, $r->{LNGW}), $r->{LATS}, $r->{LNGE}
    

    The function has to return an arrayref of arrayrefs of the points within the box

  • tile

    Returns the rendered image

REPOSITORY

https://github.com/MarkHofstetter/GoogleMapsHeatmap

AUTHOR

Mark Hofstetter hofstettm@cpan.org

Thanks to 
brian d foy
Marcel Gruenauer
David Steinbrunner

TODO

  • put more magic in calculation of zoom scales
  • make more things configurable
  • add even more tests

COPYRIGHT AND LICENSE

This software is copyright (c) 2013 by Mark Hofstetter

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.