diff options
author | Matthew Somerville <matthew-github@dracos.co.uk> | 2016-07-13 15:13:36 +0100 |
---|---|---|
committer | Dave Arter <davea@mysociety.org> | 2016-08-01 11:52:22 +0100 |
commit | 0271c3fa016178f8c72b1192f1d0ed57437ec4c4 (patch) | |
tree | 1907ce9d863fb731a802ad0c2bc8065070d4eae4 | |
parent | 8699a41fbeb79816d9852a2d1231ebd690cdd0ba (diff) |
Add static map output view for a report.
-rw-r--r-- | perllib/FixMyStreet/App/Controller/Report.pm | 11 | ||||
-rw-r--r-- | perllib/FixMyStreet/DB/Result/Problem.pm | 79 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map.pm | 5 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM.pm | 31 |
4 files changed, 113 insertions, 13 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Report.pm b/perllib/FixMyStreet/App/Controller/Report.pm index 89df4a52d..6ac3c8ea1 100644 --- a/perllib/FixMyStreet/App/Controller/Report.pm +++ b/perllib/FixMyStreet/App/Controller/Report.pm @@ -278,6 +278,17 @@ sub delete :Local :Args(1) { return $c->res->redirect($uri); } +sub map : Path('') : Args(2) { + my ( $self, $c, $id, $map ) = @_; + + $c->detach( '/page_error_404_not_found', [] ) unless $map eq 'map'; + $c->forward( 'load_problem_or_display_error', [ $id ] ); + + my $image = $c->stash->{problem}->static_map; + $c->res->content_type($image->{content_type}); + $c->res->body($image->{data}); +} + __PACKAGE__->meta->make_immutable; 1; diff --git a/perllib/FixMyStreet/DB/Result/Problem.pm b/perllib/FixMyStreet/DB/Result/Problem.pm index 1ae719361..92865ace9 100644 --- a/perllib/FixMyStreet/DB/Result/Problem.pm +++ b/perllib/FixMyStreet/DB/Result/Problem.pm @@ -161,6 +161,13 @@ use Moo; use namespace::clean -except => [ 'meta' ]; use Utils; use FixMyStreet::Map::FMS; +use LWP::Simple qw($ua); + +my $IM = eval { + require Image::Magick; + Image::Magick->import; + 1; +}; with 'FixMyStreet::Roles::Abuser', 'FixMyStreet::Roles::Extra', @@ -654,7 +661,7 @@ sub can_display_external_id { if ($self->external_id && $self->send_method_used && $self->bodies_str =~ /(2237|2550)/) { return 1; } - return 0; + return 0; } sub duration_string { @@ -836,7 +843,7 @@ __PACKAGE__->has_many( "admin_log_entries", "FixMyStreet::DB::Result::AdminLog", { "foreign.object_id" => "self.id" }, - { + { cascade_copy => 0, cascade_delete => 0, where => { 'object_type' => 'problem' }, } @@ -873,6 +880,7 @@ has get_cobrand_logged => ( }, ); + sub pin_data { my ($self, $c, $page, %opts) = @_; my $colour = $c->cobrand->pin_colour($self, $page); @@ -885,6 +893,73 @@ sub pin_data { title => $opts{private} ? $self->title : $self->title_safe, problem => $self, } +}; + +sub static_map { + my ($self) = @_; + + return unless $IM; + + my $orig_map_class = FixMyStreet::Map::set_map_class('OSM') + unless $FixMyStreet::Map::map_class->isa("FixMyStreet::Map::OSM"); + + my $map_data = $FixMyStreet::Map::map_class->generate_map_data( + { cobrand => $self->get_cobrand_logged }, + latitude => $self->latitude, + longitude => $self->longitude, + pins => $self->used_map + ? [ { + latitude => $self->latitude, + longitude => $self->longitude, + colour => $self->get_cobrand_logged->pin_colour($self, 'report'), + type => 'big', + } ] + : [], + ); + + $ua->agent("FixMyStreet/1.0"); + my $image; + for (my $i=0; $i<4; $i++) { + my $tile_url = $map_data->{tiles}->[$i]; + if ($tile_url =~ m{^//}) { + $tile_url = "https:$tile_url"; + } + my $tile = LWP::Simple::get($tile_url); + my $im = Image::Magick->new; + $im->BlobToImage($tile); + if (!$image) { + $image = $im; + $image->Extent(geometry => '512x512', gravity => 'NorthWest'); + } else { + my $gravity = ($i<2?'North':'South') . ($i%2?'East':'West'); + $image->Composite(image => $im, gravity => $gravity); + } + } + + # The only pin might be the report pin, with added x/y + my $pin = $map_data->{pins}->[0]; + if ($pin) { + my $im = Image::Magick->new; + $im->read(FixMyStreet->path_to('web', 'i', 'pin-yellow.png')); + $image->Composite(image => $im, gravity => 'NorthWest', + x => $pin->{px} - 24, y => $pin->{py} - 64); + } + + # Bottom 128/ top 64 pixels will never have a pin + $image->Extent( geometry => '512x384', gravity => 'NorthWest'); + $image->Extent( geometry => '512x320', gravity => 'SouthWest'); + + $image->Scale( geometry => "310x200>" ); + + my @blobs = $image->ImageToBlob(magick => 'jpeg'); + undef $image; + + FixMyStreet::Map::set_map_class($orig_map_class) if $orig_map_class; + + return { + data => $blobs[0], + content_type => 'image/jpeg', + }; } 1; diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm index 355fd8666..a850492b9 100644 --- a/perllib/FixMyStreet/Map.pm +++ b/perllib/FixMyStreet/Map.pm @@ -47,7 +47,8 @@ sub reload_allowed_maps { =head2 map_class -Set and return the appropriate class given a query parameter string. +Sets the appropriate class given a query parameter string. +Returns the old map class, if any. =cut @@ -57,7 +58,9 @@ sub set_map_class { $str = __PACKAGE__.'::'.$str if $str; my %avail = map { $_ => 1 } @ALL_MAP_CLASSES; $str = $ALL_MAP_CLASSES[0] unless $str && $avail{$str}; + my $old_map_class = $map_class; $map_class = $str; + return $old_map_class; } sub display_map { diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm index ae9e73a0a..d4000f1a4 100644 --- a/perllib/FixMyStreet/Map/OSM.pm +++ b/perllib/FixMyStreet/Map/OSM.pm @@ -50,6 +50,23 @@ sub copyright { sub display_map { my ($self, $c, %params) = @_; + # Map centre may be overridden in the query string + $params{latitude} = Utils::truncate_coordinate($c->get_param('lat') + 0) + if defined $c->get_param('lat'); + $params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0) + if defined $c->get_param('lon'); + + my %data; + $data{cobrand} = $c->cobrand; + $data{distance} = $c->stash->{distance}; + $data{zoom} = $c->get_param('zoom') + 0 if defined $c->get_param('zoom'); + + $c->stash->{map} = $self->generate_map_data(\%data, %params); +} + +sub generate_map_data { + my ($self, $data, %params) = @_; + my $numZoomLevels = ZOOM_LEVELS; my $zoomOffset = MIN_ZOOM_LEVEL; if ($params{any_zoom}) { @@ -58,18 +75,12 @@ sub display_map { } # Adjust zoom level dependent upon population density - my $dist = $c->stash->{distance} + my $dist = $data->{distance} || FixMyStreet::Gaze::get_radius_containing_population( $params{latitude}, $params{longitude} ); - my $default_zoom = $c->cobrand->default_map_zoom() ? $c->cobrand->default_map_zoom() : $numZoomLevels - 4; + my $default_zoom = $data->{cobrand}->default_map_zoom() || ($numZoomLevels - 4); $default_zoom = $numZoomLevels - 3 if $dist < 10; - # Map centre may be overridden in the query string - $params{latitude} = Utils::truncate_coordinate($c->get_param('lat') + 0) - if defined $c->get_param('lat'); - $params{longitude} = Utils::truncate_coordinate($c->get_param('lon') + 0) - if defined $c->get_param('lon'); - - my $zoom = defined $c->get_param('zoom') ? $c->get_param('zoom') + 0 : $default_zoom; + my $zoom = $data->{zoom} || $default_zoom; $zoom = $numZoomLevels - 1 if $zoom >= $numZoomLevels; $zoom = 0 if $zoom < 0; $params{zoom_act} = $zoomOffset + $zoom; @@ -79,7 +90,7 @@ sub display_map { ($pin->{px}, $pin->{py}) = latlon_to_px($pin->{latitude}, $pin->{longitude}, $params{x_tile}, $params{y_tile}, $params{zoom_act}); } - $c->stash->{map} = { + return { %params, type => $self->map_template(), map_type => $self->map_type(), |