File Coverage

blib/lib/Geo/Google/StaticMaps/V2.pm
Criterion Covered Total %
statement 150 173 86.7
branch 45 76 59.2
condition 6 9 66.6
subroutine 34 38 89.4
pod 20 20 100.0
total 255 316 80.7


line stmt bran cond sub pod time code
1             package Geo::Google::StaticMaps::V2;
2 10     10   252339 use warnings;
  10         24  
  10         316  
3 10     10   51 use strict;
  10         20  
  10         399  
4 10     10   52 use base qw{Package::New};
  10         22  
  10         8922  
5 10     10   2743 use File::Basename qw{};
  10         19  
  10         179  
6 10     10   8134 use Path::Class qw{file};
  10         605088  
  10         754  
7 10     10   15818 use URI qw{};
  10         60119  
  10         231  
8 10     10   11595 use LWP::UserAgent qw{};
  10         441456  
  10         295  
9 10     10   9021 use Geo::Google::StaticMaps::V2::Markers;
  10         28  
  10         285  
10 10     10   6066 use Geo::Google::StaticMaps::V2::Path;
  10         43  
  10         19365  
11              
12             our $VERSION = '0.09';
13             our $PACKAGE = __PACKAGE__;
14              
15             =head1 NAME
16              
17             Geo::Google::StaticMaps::V2 - Generate Images from Google Static Maps V2 API
18              
19             =head1 SYNOPSIS
20              
21             use Geo::Google::StaticMaps::V2;
22             my $map=Geo::Google::StaticMaps::V2->new;
23             print $map->url;
24             print $map->image;
25             $map->save("filename.png");
26              
27             =head1 DESCRIPTION
28              
29             The packages generates images from the Google Static Maps V2 API which can be saved locally for use in accordance with your license with Google.
30              
31             =head1 USAGE
32              
33             =head1 CONSTRUCTORS
34              
35             =head2 new
36              
37             use Geo::Google::StaticMaps::V2;
38             my $map=Geo::Google::StaticMaps::V2->new(
39             width => 600,
40             height => 480,
41             sensor => 0,
42             scale => 1,
43             format => "png8",
44             type => "roadmap",
45             protocol => "http",
46             server => "maps.googleapis.com",
47             script => "/maps/api/staticmap",
48             );
49              
50             Any property can be specified on construction but all have sane defaults and are not required to be set.
51              
52             =head2 marker
53              
54             Creates a L object and adds the object to the internal Markers array.
55              
56             $map->marker(location=>"7140 Main Street, Clifton, Virginia 20124");
57             $map->marker(location=>{lat=>38.780676,lon=>-77.387105});
58             $map->marker(location=>[38.780676,-77.387105]);
59             $map->marker(location=>"38.780676,-77.387105");
60              
61             markers (optional) define one or more markers to attach to the image at specified locations. Multiple markers may be placed within the same markers parameter as long as they exhibit the same style; you may add additional markers of differing styles by adding additional markers parameters. Note that if you supply markers for a map, you do not need to specify the (normally required) center and zoom parameters.
62              
63             Examples
64              
65             my $marker1=$map->marker(location=>{lat=>38.780676,lon=>-77.387105}); #isa L
66             $marker1->addLocation([38.780513,-77.387128]); #second point shares style with first point
67              
68             my $marker2=$map->marker(locations=>[
69             {lat=>38.780596,lon=>-77.386837},
70             [38.780346,-77.386923]
71             ]); #third and forth points with different style
72             $marker2->size("tiny"); #third and forth points are now tiny
73             $marker1->color("blue"); #first and second point are now blue
74              
75             =cut
76              
77             sub marker {
78 3     3 1 135 my $self=shift;
79 3         49 my $obj=Geo::Google::StaticMaps::V2::Markers->new(@_);
80 3         15 push @{$self->_markers}, $obj;
  3         18  
81 3         9 return $obj;
82             }
83              
84             #head2 _markers
85             #
86             #Returns an array reference with the current list of marker objects.
87             #
88             #cut
89              
90             sub _markers {
91 53     53   82 my $self=shift;
92 53 100       195 $self->{"_markers"}=[] unless ref($self->{"_markers"}) eq "ARRAY";
93 53         142 return $self->{"_markers"};
94             }
95              
96             =head2 path
97              
98             Creates a L object and adds the object to the internal Paths array.
99              
100             path (optional) defines a single path of two or more connected points to overlay on the image at specified locations. Note that if you supply a path for a map, you do not need to specify the (normally required) center and zoom parameters.
101              
102             =cut
103              
104             sub path {
105 5     5 1 175 my $self=shift;
106 5         69 my $obj=Geo::Google::StaticMaps::V2::Path->new(@_);
107 5         20 push @{$self->_paths}, $obj;
  5         20  
108 5         14 return $obj;
109             }
110              
111             #head2 _paths
112             #
113             #Returns an array reference with the current list of path objects.
114             #
115             #cut
116              
117             sub _paths {
118 55     55   80 my $self=shift;
119 55 100       179 $self->{"_paths"}=[] unless ref($self->{"_paths"}) eq "ARRAY";
120 55         154 return $self->{"_paths"};
121             }
122              
123             =head2 visible
124              
125             Creates a L object and adds the object to the internal Visibles array.
126              
127             visible (optional) specifies one or more locations that should remain visible on the map, though no markers or other indicators will be displayed. Use this parameter to ensure that certain features or map locations are shown on the static map.
128              
129             =cut
130              
131             sub visible {
132 1     1 1 49 my $self=shift;
133 1         14 my $obj=Geo::Google::StaticMaps::V2::Visible->new(@_);
134 1         4 push @{$self->_visibles}, $obj;
  1         7  
135 1         4 return $obj;
136             }
137              
138             #head2 _visibles
139             #
140             #Returns an array reference with the current list of visible objects.
141             #
142             ##cut
143              
144             sub _visibles {
145 51     51   76 my $self=shift;
146 51 100       181 $self->{"_visibles"}=[] unless ref($self->{"_visibles"}) eq "ARRAY";
147 51         156 return $self->{"_visibles"};
148             }
149              
150             =head1 PROPERTIES
151              
152             =head2 center
153              
154             center (required if markers not present) defines the center of the map, equidistant from all edges of the map. This parameter takes a location as either a comma-separated {latitude,longitude} pair (e.g. "40.714728,-73.998672") or a string address (e.g. "City Hall, New York, NY") identifying a unique location on the face of the earth.
155              
156             =cut
157              
158             sub center {
159 50     50 1 72 my $self=shift;
160 50 50       129 $self->{"center"}=shift if @_;
161 50         142 return $self->{"center"};
162             }
163              
164             =head2 zoom
165              
166             zoom (required if markers not present) defines the zoom level of the map, which determines the magnification level of the map. This parameter takes a numerical value corresponding to the zoom level of the region desired.
167              
168             =cut
169              
170             sub zoom {
171 50     50 1 66 my $self=shift;
172 50 50       111 $self->{"zoom"}=shift if @_;
173 50         141 return $self->{"zoom"};
174             }
175              
176             =head2 width
177              
178             Width part of size parameter.
179              
180             UOM: pixels
181              
182             Note: width of image is actually width times scale
183              
184             =cut
185              
186             sub width {
187 52     52 1 80 my $self=shift;
188 52 100       148 $self->{"width"}=shift if @_;
189 52   100     183 $self->{"width"}||=600;
190 52         170 return $self->{"width"};
191             }
192              
193             =head2 height
194              
195             Height part of size parameter
196              
197             UOM: pixels
198              
199             Note: height of image is actually height times scale
200              
201             =cut
202              
203             sub height {
204 52     52 1 78 my $self=shift;
205 52 100       121 $self->{"height"}=shift if @_;
206 52   100     152 $self->{"height"}||=400;
207 52         229 return $self->{"height"};
208             }
209              
210             =head2 sensor
211              
212             Sets or returns the sensor value true or false setting is Perlish.
213              
214             $map->sensor(0); #default
215             $map->sensor("false"); #Do not do this as "false" is true to Perl
216              
217             sensor (required) specifies whether the application requesting the static map is using a sensor to determine the user's location. This parameter is required for all static map requests.
218              
219             =cut
220              
221             sub sensor {
222 50     50 1 63 my $self=shift;
223 50 50       120 $self->{"sensor"}=shift if @_;
224 50   50     343 $self->{"sensor"}||=0;
225 50         165 return $self->{"sensor"};
226             }
227              
228             =head2 scale
229              
230             scale (optional) affects the number of pixels that are returned. scale=2 returns twice as many pixels as scale=1 while retaining the same coverage area and level of detail (i.e. the contents of the map don't change). This is useful when developing for high-resolution displays, or when generating a map for printing. The default value is 1. Accepted values are 2 and 4 (4 is only available to Maps API for Business customers.) See Scale Values for more information.
231              
232             $map->scale; #undef (default is 1; not passed on URL), 1, 2, 4
233              
234             =cut
235              
236             sub scale {
237 50     50 1 68 my $self=shift;
238 50 50       122 $self->{"scale"}=shift if @_;
239 50         153 return $self->{"scale"};
240             }
241              
242             =head2 format
243              
244             format (optional) defines the format of the resulting image. By default, the Static Maps API creates PNG images. There are several possible formats including GIF, JPEG and PNG types. Which format you use depends on how you intend to present the image. JPEG typically provides greater compression, while GIF and PNG provide greater detail. For more information, see Image Formats.
245              
246             $map->format; #undef (default is png8; not passed on URL), png8, png32, gif, jpg, jpg-baseline
247              
248             =cut
249              
250             sub format {
251 61     61 1 3071 my $self=shift;
252 61 50       258 $self->{"format"}=shift if @_;
253 61         205 return $self->{"format"};
254             }
255              
256             =head2 type
257              
258             maptype (optional) defines the type of map to construct. There are several possible maptype values, including roadmap, satellite, hybrid, and terrain.
259              
260             $map->type; #undef (default is roadmap; not passed on URL), roadmap, satellite, terrain, hybrid
261              
262             =cut
263              
264             sub type {
265 50     50 1 74 my $self=shift;
266 50 50       123 $self->{"type"}=shift if @_;
267 50         159 return $self->{"type"};
268             }
269              
270             =head2 server
271              
272             Sets or returns the Google Maps API server
273              
274             $map->server("maps.googleapis.com"); #default
275              
276             =cut
277              
278             sub server {
279 50     50 1 77 my $self=shift;
280 50 50       144 $self->{"server"}=shift if @_;
281 50 100       152 $self->{"server"}="maps.googleapis.com" unless defined($self->{"server"});
282 50         206 return $self->{"server"};
283             }
284              
285             =head2 script
286              
287             Sets or returns the script for the Google Maps API Static Map
288              
289             $map->script("/maps/api/staticmap"); #default
290              
291             =cut
292              
293             sub script {
294 50     50 1 77 my $self=shift;
295 50 50       149 $self->{"script"}=shift if @_;
296 50 100       169 $self->{"script"}="/maps/api/staticmap" unless defined($self->{"script"});
297 50         297 return $self->{"script"};
298             }
299              
300             =head2 protocol
301              
302             Sets or returns the protocol
303              
304             $map->protocol("http"); #default
305             $map->protocol("https"); #https to avoid cross security domain issues in browsers but uses more resources
306              
307             =cut
308              
309             sub protocol {
310 50     50 1 72 my $self=shift;
311 50 50       190 $self->{"protocol"}=shift if @_;
312 50 100       132 $self->{"protocol"}="http" unless defined($self->{"protocol"});
313 50         258 return $self->{"protocol"};
314             }
315              
316             #head2 _service
317             #
318             #Returns a cached URL with only "$protocol://$server"
319             #
320             #cut
321              
322             sub _service {
323 0     0   0 my $self=shift;
324 0 0       0 $self->{"_service"}=shift if @_;
325 0 0       0 unless (defined $self->{"_service"}) {
326 0         0 $self->{"_service"}=URI->new;
327 0         0 $self->{"_service"}->scheme($self->protocol);
328 0         0 $self->{"_service"}->host($self->server);
329             }
330 0         0 return $self->{"_service"};
331             }
332              
333             =head1 METHODS
334              
335             =head2 image
336              
337             Returns the image as a binary scalar.
338              
339             my $blob=$map->image;
340              
341             See: L
342              
343             =cut
344              
345             sub image {
346 3     3 1 6 my $self=shift;
347 3         14 my $response=$self->_ua->get($self->url);
348 3 50       249723 if ($response->is_success) {
349 3         63 return $response->decoded_content;
350             } else {
351 0         0 die $response->status_line;
352             }
353             }
354              
355             #head2 _ua
356             #
357             #Returns a cached LWP::UserAgent object
358             #
359             #cut
360              
361             sub _ua {
362 3     3   7 my $self=shift;
363 3 100       13 unless (defined $self->{"_ua"}) {
364 1         13 $self->{"_ua"}=LWP::UserAgent->new;
365 1         3883 $self->{"_ua"}->timeout(10);
366 1         27 $self->{"_ua"}->env_proxy;
367             }
368 3         22342 return $self->{"_ua"};
369             }
370              
371             =head2 save
372              
373             Saves image to the local file system.
374              
375             $map->save("image.png");
376             $map->save("image.gif");
377             $map->save("image.jpg");
378              
379             Note: If you have not explicitly set the format, the save method will guess the format from the extension.
380              
381             =cut
382              
383             sub save {
384 3     3 1 10 my $self = shift;
385 3         5 my $filename = shift;
386 3         10 my $suffix = (File::Basename::fileparse($filename, keys(%{$self->_extensions})))[2];
  3         12  
387 3 50 33     17 local $self->{"format"}=$self->_extensions->{$suffix}
388             if (exists($self->_extensions->{$suffix}) && !defined($self->format));
389 3         27 my $file=file($filename); #isa Path::Class::File
390 3         350 my $fh=$file->openw;
391 3         727 print $fh $self->image;
392 3         1484 return $self;
393             }
394              
395             sub _extensions {
396 9     9   347 return {".png" => undef, ".gif" => "gif", ".jpg" => "jpg"};
397             }
398              
399             =head2 url
400              
401             Returns the URL for the Static map. If L is installed and configured the URL is seamlessly signed with your Google Enterprise Key.
402              
403             my $url=$map->url; #isa L
404              
405             =cut
406              
407             sub url {
408 50     50 1 5632 my $self=shift;
409 50         152 my $url=URI->new($self->script); #isa URI
410 50         54687 my @q=();
411 50         196 push @q, size => $self->_size; #required
412 50 50       147 push @q, maptype => $self->type if defined $self->type;
413 50 50       131 push @q, scale => $self->scale if defined $self->scale;
414 50 100       127 push @q, format => $self->format if defined $self->format;
415 50 50       136 push @q, sensor => $self->sensor ? "true" : "false";
416 50         69 my $needs_view=1;
417 50         70 foreach my $visible (@{$self->_visibles}) {
  50         125  
418 6         6 $needs_view=0;
419 6         24 push @q, visible => $visible->stringify;
420             }
421 50         79 foreach my $marker (@{$self->_markers}) {
  50         153  
422 20         30 $needs_view=0;
423 20         108 push @q, markers => $marker->stringify;
424             }
425 50         74 foreach my $path (@{$self->_paths}) {
  50         128  
426 24         31 $needs_view=0;
427 24         120 push @q, path => $path->stringify;
428             }
429 50 50       209 if (defined $self->center) {
430 0         0 push @q, center => $self->center;
431             } else {
432 50 100       149 push @q, center => "Clifton, VA" if $needs_view; #we should only get here in the trival case
433             }
434 50 50       118 if (defined $self->zoom) {
435 0         0 push @q, zoom => $self->zoom;
436             } else {
437 50 100       107 push @q, zoom => "7" if $needs_view; #we should only get here in the trival case
438             }
439 50         228 $url->query_form(@q);
440 50 50       13153 if ($self->_signer) {
441 0         0 $url=$self->_signer->url($self->_service => $url);
442             } else {
443 50         146 $url->scheme($self->protocol);
444 50         38896 $url->host($self->server);
445             }
446 50         9252 return $url;
447             }
448              
449             #head2 _size
450             #
451             #size (required) defines the rectangular dimensions of the map image. This parameter takes a string of the form {horizontal_value}x{vertical_value}. For example, 500x400 defines a map 500 pixels wide by 400 pixels high. Maps smaller than 180 pixels in width will display a reduced-size Google logo. This parameter is affected by the scale parameter, described below; the final output size is the product of the size and scale values.
452             #
453             #cut
454              
455             sub _size {
456 50     50   82 my $self=shift;
457 50         142 return join("x", $self->width, $self->height);
458             }
459              
460             #head2 _signer
461             #
462             #Returns false but defined or a cached L<> object
463             #
464             #Note: This method returns false if the URL::Signature::Google::Maps::API is not installed and thus URL signatures will not be available.
465             #
466             #cut
467              
468             sub _signer {
469 50     50   82 my $self=shift;
470 50 50       124 $self->{"_signer"}=shift if @_;
471 50 100       147 unless (defined $self->{"_signer"}) { #init
472 1     1   113 eval('use URL::Signature::Google::Maps::API');
  1         693  
  0            
  0            
473 1 50       5 if ($@) {
474 1         12 $self->{"_signer"}="";
475             } else {
476 0 0       0 $self->{"_signer"}=URL::Signature::Google::Maps::API->new(channel=>$self->channel, client=>$self->client, key=>$self->key)
477             unless defined($self->{"_signer"});
478             }
479             }
480 50         146 return $self->{"_signer"};
481             }
482              
483             =head1 Google Enterprise Credentials
484              
485             These settings are simply passed through to L.
486              
487             I recommend storing the credentials in the INI formatted file and leaving these values as undef.
488              
489             =head2 client
490              
491             Sets and returns the Google Enterprise Client
492              
493             =cut
494              
495             sub client {
496 0     0 1 0 my $self=shift;
497 0 0       0 $self->{"client"}=shift if @_;
498 0         0 return $self->{"client"};
499             }
500              
501             =head2 key
502              
503             Sets and returns the Google Enterprise Key
504              
505             =cut
506              
507             sub key {
508 0     0 1 0 my $self=shift;
509 0 0       0 $self->{"key"}=shift if @_;
510 0         0 return $self->{"key"};
511             }
512              
513             =head2 channel
514              
515             Sets and returns the Google Enterprise channel.
516              
517             =cut
518              
519             sub channel {
520 0     0 1 0 my $self=shift;
521 0 0       0 $self->{"channel"}=shift if @_;
522 0         0 return $self->{"channel"};
523             }
524              
525             =head1 BUGS
526              
527             Please log on RT and send an email to the author.
528              
529             =head1 SUPPORT
530              
531             DavisNetworks.com supports all Perl applications including this package.
532              
533             =head1 AUTHOR
534              
535             Michael R. Davis
536             CPAN ID: MRDVT
537             Satellite Tracking of People, LLC
538             mdavis@stopllc.com
539             http://www.stopllc.com/
540              
541             =head1 COPYRIGHT
542              
543             This program is free software licensed under the...
544              
545             The General Public License (GPL) Version 2, June 1991
546              
547             The full text of the license can be found in the LICENSE file included with this module.
548              
549             =head1 SEE ALSO
550              
551             L, L, L, L
552              
553             =cut
554              
555             1;