diff options
Diffstat (limited to 'perllib')
-rw-r--r-- | perllib/Cobrand.pm | 2 | ||||
-rw-r--r-- | perllib/Cobrands/Barnet/Util.pm | 4 | ||||
-rw-r--r-- | perllib/Cobrands/Fiksgatami/Util.pm | 10 | ||||
-rw-r--r-- | perllib/Cobrands/Southampton/Util.pm | 117 | ||||
-rw-r--r-- | perllib/FixMyStreet/Alert.pm | 1 | ||||
-rw-r--r-- | perllib/FixMyStreet/Geocode.pm | 55 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map.pm | 120 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Bing.pm | 32 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/BingOL.pm | 38 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Google.pm | 30 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM.pm | 176 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM/CycleMap.pm | 61 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/OSM/StreetView.pm | 32 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm | 32 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm | 32 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/Original.pm | 124 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/Original/1_10k.pm | 24 | ||||
-rw-r--r-- | perllib/FixMyStreet/Map/Tilma/Original/StreetView.pm | 23 | ||||
-rw-r--r-- | perllib/Page.pm | 57 |
19 files changed, 616 insertions, 354 deletions
diff --git a/perllib/Cobrand.pm b/perllib/Cobrand.pm index fa2dd9e88..b1ec6ba75 100644 --- a/perllib/Cobrand.pm +++ b/perllib/Cobrand.pm @@ -119,6 +119,8 @@ my %fns = ( # The MaPit types this site handles 'area_types' => { default => '[qw(DIS LBO MTD UTA CTY COI)]' }, 'area_min_generation' => { default => '10' }, + # Some cobrands that use a Tilma map have a smaller mid-point to make pin centred + 'tilma_mid_point' => { default => '""' }, ); foreach (keys %fns) { diff --git a/perllib/Cobrands/Barnet/Util.pm b/perllib/Cobrands/Barnet/Util.pm index 0e5ddcf68..e4115c232 100644 --- a/perllib/Cobrands/Barnet/Util.pm +++ b/perllib/Cobrands/Barnet/Util.pm @@ -109,5 +109,9 @@ sub recent_photos { return Problems::recent_photos($num, $lat, $lon, $dist); } +sub tilma_mid_point { + return 189; +} + 1; diff --git a/perllib/Cobrands/Fiksgatami/Util.pm b/perllib/Cobrands/Fiksgatami/Util.pm index 38366f0e1..2abc03d00 100644 --- a/perllib/Cobrands/Fiksgatami/Util.pm +++ b/perllib/Cobrands/Fiksgatami/Util.pm @@ -22,6 +22,16 @@ sub set_lang_and_domain { mySociety::Locale::change(); } +# If lat/lon are present in the URL, OpenLayers will use that to centre the map. +# Need to specify a zoom to stop it defaulting to null/0. +sub url { + my ($self, $url) = @_; + if ($url =~ /lat=/ && $url !~ /zoom=/) { + $url .= ';zoom=2'; + } + return $url; +} + sub enter_postcode_text { my ($self, $q) = @_; return _('Enter a nearby postcode, or street name and area'); diff --git a/perllib/Cobrands/Southampton/Util.pm b/perllib/Cobrands/Southampton/Util.pm new file mode 100644 index 000000000..d29b53127 --- /dev/null +++ b/perllib/Cobrands/Southampton/Util.pm @@ -0,0 +1,117 @@ +#!/usr/bin/perl -w +# +# Util.pm: +# Southampton cobranding for FixMyStreet. +# +# Copyright (c) 2011 UK Citizens Online Democracy. All rights reserved. +# Email: matthew@mysociety.org. WWW: http://www.mysociety.org + +package Cobrands::Southampton::Util; +use strict; +use Carp; +use URI::Escape; +use mySociety::VotingArea; + +sub new { + my $class = shift; + return bless {}, $class; +} + +=item site_restriction Q + +Return a site restriction clause and a site key. + +=cut +sub site_restriction { + return ("and council='2567'", 'southampton'); +} + +=item + +Return the base url for this cobranded site + +=cut + +sub base_url { + my $base_url = mySociety::Config::get('BASE_URL'); + if ($base_url !~ /southampton/) { + $base_url =~ s/http:\/\/(?!www\.)/http:\/\/southampton\./g; + $base_url =~ s/http:\/\/www\./http:\/\/southampton\./g; + } + return $base_url; +} + +=item site_title + +Return the title to be used in page heads + +=cut + +sub site_title { + my ($self) = @_; + return 'Southampton City Council FixMyStreet'; +} + +sub enter_postcode_text { + my ($self,$q) = @_; + return 'Enter a Southampton postcode, or street name and area'; +} + +=item council_check COUNCILS QUERY CONTEXT + +Return a boolean indicating whether COUNCILS are okay for the location +in the QUERY, and an error message appropriate to the CONTEXT. + +=cut + +sub council_check { + my ($self, $params, $q, $context) = @_; + my $councils; + if ($params->{all_councils}) { + $councils = $params->{all_councils}; + } elsif (defined $params->{lat}) { + my $parent_types = $mySociety::VotingArea::council_parent_types; + $councils = mySociety::MaPit::call('point', "4326/$params->{lon},$params->{lat}", type => $parent_types); + } + my $council_match = defined $councils->{2567}; + if ($council_match) { + return 1; + } + my $url = 'http://www.fixmystreet.com/'; + $url .= 'alert' if $context eq 'alert'; + $url .= '?pc=' . URI::Escape::uri_escape_utf8($q->param('pc')) if $q->param('pc'); + my $error_msg = "That location is not covered by Southampton. +Please visit <a href=\"$url\">the main FixMyStreet site</a>."; + return (0, $error_msg); +} + +# All reports page only has the one council. +sub all_councils_report { + return 0; +} + +=item disambiguate_location S Q + +Given a string representing a location (street and area expected), +bias the viewport to around Southampton. + +=cut + +sub disambiguate_location { + my ($self, $s, $q) = @_; + $s = "ll=50.913822,-1.400493&spn=0.084628,0.15701&$s"; + return $s; +} + +sub recent_photos { + my ($self, $num, $lat, $lon, $dist) = @_; + $num = 2 if $num == 3; + return Problems::recent_photos($num, $lat, $lon, $dist); +} + +sub tilma_mid_point { + return 189; +} + +1; + diff --git a/perllib/FixMyStreet/Alert.pm b/perllib/FixMyStreet/Alert.pm index 29932a0a5..cfe9c1781 100644 --- a/perllib/FixMyStreet/Alert.pm +++ b/perllib/FixMyStreet/Alert.pm @@ -298,6 +298,7 @@ sub generate_rss ($$$;$$$$) { description => ent(ent($desc)) # Yes, double-encoded, really. ); $item{pubDate} = $pubDate if $pubDate; + $item{category} = $row->{category} if $row->{category}; my $display_photos = Cobrand::allow_photo_display($cobrand); if ($display_photos && $row->{photo}) { diff --git a/perllib/FixMyStreet/Geocode.pm b/perllib/FixMyStreet/Geocode.pm index 803e32a85..c06c3bb55 100644 --- a/perllib/FixMyStreet/Geocode.pm +++ b/perllib/FixMyStreet/Geocode.pm @@ -50,6 +50,14 @@ sub lookup { $longitude = $location->{wgs84_lon}; } } + } elsif (mySociety::Config::get('COUNTRY') eq 'NO') { + if ($s =~ /^\d{4}$/) { + my $location = mySociety::MaPit::call('postcode', $s); + unless ($error = Page::mapit_check_error($location)) { + $latitude = $location->{wgs84_lat}; + $longitude = $location->{wgs84_lon}; + } + } } unless ($error || defined $latitude) { ($latitude, $longitude, $error) = FixMyStreet::Geocode::string($s, $q); @@ -80,15 +88,31 @@ sub geocoded_string_coordinates { return ($latitude, $longitude, $error); } +sub results_check { + my $q = shift; + my ($error, @valid_locations); + foreach (@_) { + next unless /"address" *: *"(.*?)"/s; + my $address = $1; + next unless Cobrand::geocoded_string_check(Page::get_cobrand($q), $address, $q); + next if $address =~ /BT\d/; + push (@$error, $address); + push (@valid_locations, $_); + } + if (scalar @valid_locations == 1) { + return geocoded_string_coordinates($valid_locations[0], $q); + } + $error = _('Sorry, we could not find that location.') unless $error; + return (undef, undef, $error); +} + # string STRING QUERY # Canonicalises, looks up on Google Maps API, and caches, a user-inputted location. -# Returns array of (TILE_X, TILE_Y, EASTING, NORTHING, ERROR), where ERROR is -# either undef, a string, or an array of matches if there are more than one. The -# information in the query may be used to disambiguate the location in cobranded versions -# of the site. +# Returns array of (LAT, LON, ERROR), where ERROR is either undef, a string, or +# an array of matches if there are more than one. The information in the query +# may be used to disambiguate the location in cobranded versions of the site. sub string { my ($s, $q) = @_; - $s = decode_utf8($s); $s = lc($s); $s =~ s/[^-&\w ']/ /g; $s =~ s/\s+/ /g; @@ -98,7 +122,7 @@ sub string { my $url = 'http://maps.google.com/maps/geo?' . $s; my $cache_dir = mySociety::Config::get('GEO_CACHE'); my $cache_file = $cache_dir . md5_hex($url); - my ($js, $error, $latitude, $longitude); + my ($js, $error); if (-s $cache_file) { $js = File::Slurp::read_file($cache_file); } else { @@ -115,27 +139,14 @@ sub string { } elsif ($js !~ /"code" *: *200/) { $error = _('Sorry, we could not find that location.'); } elsif ($js =~ /}, *{/) { # Multiple - my @js = split /}, *{/, $js; - my @valid_locations; - foreach (@js) { - next unless /"address" *: *"(.*?)"/s; - my $address = $1; - next unless Cobrand::geocoded_string_check(Page::get_cobrand($q), $address, $q); - next if $address =~ /BT\d/; - push (@valid_locations, $_); - push (@$error, $address); - } - if (scalar @valid_locations == 1) { - return geocoded_string_coordinates($valid_locations[0], $q); - } - $error = _('Sorry, we could not find that location.') unless $error; + return results_check($q, (split /}, *{/, $js)); } elsif ($js =~ /BT\d/) { # Northern Ireland, hopefully $error = _("We do not cover Northern Ireland, I'm afraid, as our licence doesn't include any maps for the region."); } else { - ($latitude, $longitude, $error) = geocoded_string_coordinates($js, $q); + return results_check($q, $js); } - return ($latitude, $longitude, $error); + return (undef, undef, $error); } # list_choices diff --git a/perllib/FixMyStreet/Map.pm b/perllib/FixMyStreet/Map.pm index edb4fedc9..62dab454b 100644 --- a/perllib/FixMyStreet/Map.pm +++ b/perllib/FixMyStreet/Map.pm @@ -10,25 +10,64 @@ package FixMyStreet::Map; use strict; +use Module::Pluggable + sub_name => 'maps', + search_path => __PACKAGE__, + except => 'FixMyStreet::Map::Tilma::Original', + require => 1; + +# Get the list of maps we want and load map classes at compile time +my @ALL_MAP_CLASSES = allowed_maps(); + use Problems; use Cobrand; use mySociety::Config; use mySociety::Gaze; use mySociety::Locale; -use mySociety::Web qw(ent NewURL); -use Utils; +use mySociety::Web qw(ent); + +=head2 allowed_maps + +Returns an array of all the map classes that were found and that +are permitted by the config. + +=cut + +sub allowed_maps { + my @allowed = split /,/, mySociety::Config::get('MAP_TYPE'); + @allowed = map { __PACKAGE__.'::'.$_ } @allowed; + my %avail = map { $_ => 1 } __PACKAGE__->maps; + return grep { $avail{$_} } @allowed; +} + +=head2 map_class + +Set and return the appropriate class given a query parameter string. + +=cut + +our $map_class; +sub set_map_class { + my $str = shift; + $str = __PACKAGE__.'::'.$str if $str; + my %avail = map { $_ => 1 } @ALL_MAP_CLASSES; + $str = $ALL_MAP_CLASSES[0] unless $str && $avail{$str}; + $map_class = $str; +} -# Run on module boot up -load(); +sub header_js { + return $map_class->header_js(@_); +} -# This is yucky, but no-one's taught me a better way -sub load { - my $type = mySociety::Config::get('MAP_TYPE'); - my $class = "FixMyStreet::Map::$type"; - eval "use $class"; +sub display_map { + return $map_class->display_map(@_); +} - # If we have an error die as it is a compile error rather than runtime error - die $@ if $@; +sub display_map_end { + my ($type) = @_; + my $out = '</div>'; + $out .= '</form>' if ($type); + return $out; } sub header { @@ -41,29 +80,17 @@ sub header { my $form_action = Cobrand::url( $cobrand, '/report/new', $q ); my $encoding = ''; $encoding = ' enctype="multipart/form-data"' if $type == 2; - my $pc = $q->param('pc') || ''; - my $pc_enc = ent($pc); + my $pc = ent($q->param('pc') || ''); + my $map = ent($q->param('map') || ''); return <<EOF; <form action="$form_action" method="post" name="mapForm" id="mapForm"$encoding> <input type="hidden" name="submit_map" value="1"> -<input type="hidden" name="pc" value="$pc_enc"> +<input type="hidden" name="map" value="$map"> +<input type="hidden" name="pc" value="$pc"> $cobrand_form_elements EOF } -=head2 map_features_easting_northing - -Wrapper around map_features which does the easting, northing to lat, lon -conversion. - -=cut - -sub map_features_easting_northing { - my ( $q, $easting, $northing, $interval ) = @_; - my ( $lat, $lon ) = Utils::convert_en_to_latlon( $easting, $northing ); - return map_features( $q, $lat, $lon, $interval ); -} - sub map_features { my ( $q, $lat, $lon, $interval ) = @_; @@ -102,35 +129,16 @@ sub map_features { return ( $around_map, $around_map_list, $nearby, $dist ); } -sub compass ($$$) { - my ( $q, $x, $y ) = @_; - my @compass; - for ( my $i = $x - 1 ; $i <= $x + 1 ; $i++ ) { - for ( my $j = $y - 1 ; $j <= $y + 1 ; $j++ ) { - $compass[$i][$j] = NewURL( $q, x => $i, y => $j ); - } - } - my $recentre = NewURL($q); - my $host = Page::base_url_with_lang( $q, undef ); - return <<EOF; -<table cellpadding="0" cellspacing="0" border="0" id="compass"> -<tr valign="bottom"> -<td align="right"><a rel="nofollow" href="${compass[$x-1][$y+1]}"><img src="$host/i/arrow-northwest.gif" alt="NW" width=11 height=11></a></td> -<td align="center"><a rel="nofollow" href="${compass[$x][$y+1]}"><img src="$host/i/arrow-north.gif" vspace="3" alt="N" width=13 height=11></a></td> -<td><a rel="nofollow" href="${compass[$x+1][$y+1]}"><img src="$host/i/arrow-northeast.gif" alt="NE" width=11 height=11></a></td> -</tr> -<tr> -<td><a rel="nofollow" href="${compass[$x-1][$y]}"><img src="$host/i/arrow-west.gif" hspace="3" alt="W" width=11 height=13></a></td> -<td align="center"><a rel="nofollow" href="$recentre"><img src="$host/i/rose.gif" alt="Recentre" width=35 height=34></a></td> -<td><a rel="nofollow" href="${compass[$x+1][$y]}"><img src="$host/i/arrow-east.gif" hspace="3" alt="E" width=11 height=13></a></td> -</tr> -<tr valign="top"> -<td align="right"><a rel="nofollow" href="${compass[$x-1][$y-1]}"><img src="$host/i/arrow-southwest.gif" alt="SW" width=11 height=11></a></td> -<td align="center"><a rel="nofollow" href="${compass[$x][$y-1]}"><img src="$host/i/arrow-south.gif" vspace="3" alt="S" width=13 height=11></a></td> -<td><a rel="nofollow" href="${compass[$x+1][$y-1]}"><img src="$host/i/arrow-southeast.gif" alt="SE" width=11 height=11></a></td> -</tr> -</table> -EOF +sub map_pins { + return $map_class->map_pins(@_); +} + +sub click_to_wgs84 { + return $map_class->click_to_wgs84(@_); +} + +sub tile_xy_to_wgs84 { + return $map_class->tile_xy_to_wgs84(@_); } 1; diff --git a/perllib/FixMyStreet/Map/Bing.pm b/perllib/FixMyStreet/Map/Bing.pm index 8446a10fd..335759b08 100644 --- a/perllib/FixMyStreet/Map/Bing.pm +++ b/perllib/FixMyStreet/Map/Bing.pm @@ -6,10 +6,9 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Bing; use strict; -use mySociety::GeoUtil; use mySociety::Web qw(ent); sub header_js { @@ -27,21 +26,29 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + my @pins; foreach my $pin (@{$params{pins}}) { + $pin->[3] ||= ''; + push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; } + my $pins_js = join(",\n", @pins); my $out = FixMyStreet::Map::header($q, $params{type}); - my ($lat, $lon) = mySociety::GeoUtil::national_grid_to_wgs84($params{easting}, $params{northing}, 'G'); my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); + my $key = mySociety::Config::get('BING_MAPS_API_KEY'); $out .= <<EOF; +<input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> <script type="text/javascript"> var fixmystreet = { - 'lat': $lat, - 'lon': $lon + 'key': '$key', + 'latitude': $params{latitude}, + 'longitude': $params{longitude}, + 'pins': [ $pins_js ] } </script> <div id="map_box"> @@ -55,17 +62,4 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { -} - 1; diff --git a/perllib/FixMyStreet/Map/BingOL.pm b/perllib/FixMyStreet/Map/BingOL.pm index 3939a710f..4e93243a9 100644 --- a/perllib/FixMyStreet/Map/BingOL.pm +++ b/perllib/FixMyStreet/Map/BingOL.pm @@ -1,12 +1,12 @@ #!/usr/bin/perl # -# FixMyStreet:Map::Bing -# Bing maps on FixMyStreet. +# FixMyStreet:Map::BingOL +# Bing maps on FixMyStreet, using OpenLayers. # -# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. +# Copyright (c) 2011 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::BingOL; use strict; use mySociety::Web qw(ent); @@ -14,9 +14,9 @@ use mySociety::Web qw(ent); sub header_js { return ' <!-- <script type="text/javascript" src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=7.0&mkt=en-GB"></script> --> -<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/jslib/OpenLayers-2.10/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenLayers.js"></script> <script type="text/javascript" src="/js/map-bing-ol.js"></script> -<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> '; } @@ -28,20 +28,27 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + my @pins; foreach my $pin (@{$params{pins}}) { + $pin->[3] ||= ''; + push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; } + my $pins_js = join(",\n", @pins); my $out = FixMyStreet::Map::header($q, $params{type}); my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010. Microsoft'); $out .= <<EOF; +<input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> <script type="text/javascript"> var fixmystreet = { - 'easting': $params{easting}, - 'northing': $params{northing} + 'latitude': $params{latitude}, + 'longitude': $params{longitude}, + 'pins': [ $pins_js ] } </script> <div id="map_box"> @@ -55,17 +62,4 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { -} - 1; diff --git a/perllib/FixMyStreet/Map/Google.pm b/perllib/FixMyStreet/Map/Google.pm index 7a314efad..35896108b 100644 --- a/perllib/FixMyStreet/Map/Google.pm +++ b/perllib/FixMyStreet/Map/Google.pm @@ -6,10 +6,9 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Google; use strict; -use mySociety::GeoUtil; use mySociety::Web qw(ent); sub header_js { @@ -27,21 +26,27 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + my @pins; foreach my $pin (@{$params{pins}}) { + $pin->[3] ||= ''; + push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; } + my $pins_js = join(",\n", @pins); my $out = FixMyStreet::Map::header($q, $params{type}); - my ($lat, $lon) = mySociety::GeoUtil::national_grid_to_wgs84($params{easting}, $params{northing}, 'G'); my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); $out .= <<EOF; +<input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> <script type="text/javascript"> var fixmystreet = { - 'lat': $lat, - 'lon': $lon + 'latitude': $params{latitude}, + 'longitude': $params{longitude}, + 'pins': [ $pins_js ] } </script> <div id="map_box"> @@ -55,17 +60,4 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { -} - 1; diff --git a/perllib/FixMyStreet/Map/OSM.pm b/perllib/FixMyStreet/Map/OSM.pm index 7953d16e2..b930a4e4d 100644 --- a/perllib/FixMyStreet/Map/OSM.pm +++ b/perllib/FixMyStreet/Map/OSM.pm @@ -6,18 +6,25 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::OSM; use strict; -use mySociety::Web qw(ent); +use Math::Trig; +use mySociety::Web qw(ent NewURL); +use Utils; sub header_js { return ' <script type="text/javascript" src="/jslib/OpenLayers-2.10/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenLayers.js"></script> <script type="text/javascript" src="/js/map-OpenStreetMap.js"></script> '; } +sub map_type { + return 'OpenLayers.Layer.OSM.Mapnik'; +} + # display_map Q PARAMS # PARAMS include: # latitude, longitude for the centre point of the map @@ -26,33 +33,68 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + # Map centre may be overridden in the query string + $params{latitude} = Utils::truncate_coordinate($q->param('lat')+0) + if defined $q->param('lat'); + $params{longitude} = Utils::truncate_coordinate($q->param('lon')+0) + if defined $q->param('lon'); + + my $zoom = defined $q->param('zoom') ? $q->param('zoom') : 2; + my $zoom_act = 14 + $zoom; + my ($x_tile, $y_tile) = latlon_to_tile_with_adjust($params{latitude}, $params{longitude}, $zoom_act); + + my $tl = ($x_tile-1) . "/" . ($y_tile-1); + my $tr = "$x_tile/" . ($y_tile-1); + my $bl = ($x_tile-1) . "/$y_tile"; + my $br = "$x_tile/$y_tile"; + my $tl_src = "http://a.tile.openstreetmap.org/$zoom_act/$tl.png"; + my $tr_src = "http://b.tile.openstreetmap.org/$zoom_act/$tr.png"; + my $bl_src = "http://c.tile.openstreetmap.org/$zoom_act/$bl.png"; + my $br_src = "http://tile.openstreetmap.org/$zoom_act/$br.png"; + map { s{/}{.} } ($tl, $tr, $bl, $br); + my @pins; + my $pins = ''; foreach my $pin (@{$params{pins}}) { $pin->[3] ||= ''; push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; + $pins .= display_pin($q, $pin, $x_tile, $y_tile, $zoom_act); } - my $pins = join(",\n", @pins); + my $pins_js = join(",\n", @pins); + my $img_type; + if ($params{type}) { + $img_type = '<input type="image"'; + } else { + $img_type = '<img'; + } my $out = FixMyStreet::Map::header($q, $params{type}); - my $copyright = _('Map © <a href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'); + my $copyright = _('Map © <a id="osm_link" href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'); + my $compass = compass($q, $x_tile, $y_tile, $zoom); + my $map_type = $self->map_type(); $out .= <<EOF; <input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> <input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> +<input type="hidden" name="zoom" value="$zoom"> <script type="text/javascript"> var fixmystreet = { 'latitude': $params{latitude}, 'longitude': $params{longitude}, - 'pins': [ $pins ], - 'map_type': OpenLayers.Layer.OSM.Mapnik + 'pins': [ $pins_js ], + 'map_type': $map_type } </script> <div id="map_box"> $params{pre} - <div id="map"></div> + <div id="map"><noscript> + <div id="drag">$img_type alt="NW map tile" id="t2.2" name="tile_$tl" src="$tl_src" style="top:0; left:0;">$img_type alt="NE map tile" id="t2.3" name="tile_$tr" src="$tr_src" style="top:0px; left:256px;"><br>$img_type alt="SW map tile" id="t3.2" name="tile_$bl" src="$bl_src" style="top:256px; left:0;">$img_type alt="SE map tile" id="t3.3" name="tile_$br" src="$br_src" style="top:256px; left:256px;"></div> + <div id="pins">$pins</div> + $compass + </noscript></div> <p id="copyright">$copyright</p> $params{post} </div> @@ -61,17 +103,123 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); +sub display_pin { + my ($q, $pin, $x_tile, $y_tile, $zoom) = @_; + + my ($px, $py) = latlon_to_px($pin->[0], $pin->[1], $x_tile, $y_tile, $zoom); + + my $num = ''; + my $host = Page::base_url_with_lang($q, undef); + my %cols = (red=>'R', green=>'G', blue=>'B', purple=>'P'); + my $out = '<img border="0" class="pin" src="' . $host . '/i/pin' . $cols{$pin->[2]} + . $num . '.gif" alt="' . _('Problem') . '" style="top:' . ($py-59) + . 'px; left:' . ($px) . 'px; position: absolute;">'; + return $out unless $pin->[3]; + my $cobrand = Page::get_cobrand($q); + my $url = Cobrand::url($cobrand, NewURL($q, -url => '/report/' . $pin->[3]), $q); + # XXX Would like to include title here in title="" + $out = '<a href="' . $url . '">' . $out . '</a>'; return $out; } -sub display_pin { +# Given a lat/lon, convert it to OSM tile co-ordinates (precise). +sub latlon_to_tile($$$) { + my ($lat, $lon, $zoom) = @_; + my $x_tile = ($lon + 180) / 360 * 2**$zoom; + my $y_tile = (1 - log(tan(deg2rad($lat)) + sec(deg2rad($lat))) / pi) / 2 * 2**$zoom; + return ( $x_tile, $y_tile ); +} + +# Given a lat/lon, convert it to OSM tile co-ordinates (nearest actual tile, +# adjusted so the point will be near the centre of a 2x2 tiled map). +sub latlon_to_tile_with_adjust($$$) { + my ($lat, $lon, $zoom) = @_; + my ($x_tile, $y_tile) = latlon_to_tile($lat, $lon, $zoom); + + # Try and have point near centre of map + if ($x_tile - int($x_tile) > 0.5) { + $x_tile += 1; + } + if ($y_tile - int($y_tile) > 0.5) { + $y_tile += 1; + } + + return ( int($x_tile), int($y_tile) ); +} + +sub tile_to_latlon { + my ($x, $y, $zoom) = @_; + my $n = 2 ** $zoom; + my $lon = $x / $n * 360 - 180; + my $lat = rad2deg(atan(sinh(pi * (1 - 2 * $y / $n)))); + return ( $lat, $lon ); +} + +# Given a lat/lon, convert it to pixel co-ordinates from the top left of the map +sub latlon_to_px($$$$$) { + my ($lat, $lon, $x_tile, $y_tile, $zoom) = @_; + my ($pin_x_tile, $pin_y_tile) = latlon_to_tile($lat, $lon, $zoom); + my $pin_x = tile_to_px($pin_x_tile, $x_tile); + my $pin_y = tile_to_px($pin_y_tile, $y_tile); + return ($pin_x, $pin_y); +} + +# Convert tile co-ordinates to pixel co-ordinates from top left of map +# C is centre tile reference of displayed map +sub tile_to_px { + my ($p, $c) = @_; + $p = 256 * ($p - $c + 1); + $p = int($p + .5 * ($p <=> 0)); + return $p; } -sub map_pins { +sub click_to_tile { + my ($pin_tile, $pin) = @_; + $pin -= 256 while $pin > 256; + $pin += 256 while $pin < 0; + return $pin_tile + $pin / 256; +} + +# Given some click co-ords (the tile they were on, and where in the +# tile they were), convert to WGS84 and return. +sub click_to_wgs84 { + my ($self, $q, $pin_tile_x, $pin_x, $pin_tile_y, $pin_y) = @_; + my $tile_x = click_to_tile($pin_tile_x, $pin_x); + my $tile_y = click_to_tile($pin_tile_y, $pin_y); + my $zoom = 14 + (defined $q->param('zoom') ? $q->param('zoom') : 2); + my ($lat, $lon) = tile_to_latlon($tile_x, $tile_y, $zoom); + return ( $lat, $lon ); +} + +sub compass ($$$$) { + my ( $q, $x, $y, $zoom ) = @_; + + my ($lat, $lon) = map { Utils::truncate_coordinate($_) } tile_to_latlon($x, $y-1, $zoom+14); + my $north = NewURL( $q, lat => $lat, lon => $lon, zoom => $zoom ); + ($lat, $lon) = map { Utils::truncate_coordinate($_) } tile_to_latlon($x, $y+1, $zoom+14); + my $south = NewURL( $q, lat => $lat, lon => $lon, zoom => $zoom ); + ($lat, $lon) = map { Utils::truncate_coordinate($_) } tile_to_latlon($x-1, $y, $zoom+14); + my $west = NewURL( $q, lat => $lat, lon => $lon, zoom => $zoom ); + ($lat, $lon) = map { Utils::truncate_coordinate($_) } tile_to_latlon($x+1, $y, $zoom+14); + my $east = NewURL( $q, lat => $lat, lon => $lon, zoom => $zoom ); + ($lat, $lon) = map { Utils::truncate_coordinate($_) } tile_to_latlon($x, $y, $zoom+14); + my $zoom_in = $zoom < 3 ? NewURL( $q, lat => $lat, lon => $lon, zoom => $zoom+1 ) : '#'; + my $zoom_out = $zoom > 0 ? NewURL( $q, lat => $lat, lon => $lon, zoom => $zoom-1 ) : '#'; + my $world = NewURL( $q, lat => $lat, lon => $lon, zoom => 0 ); + + #my $host = Page::base_url_with_lang( $q, undef ); + my $dir = "/jslib/OpenLayers-2.10/img"; + return <<EOF; +<div style="position: absolute; left: 4px; top: 4px; z-index: 1007;" class="olControlPanZoom olControlNoSelect" unselectable="on"> + <div style="position: absolute; left: 13px; top: 4px; width: 18px; height: 18px;"><a href="$north"><img style="position: relative; width: 18px; height: 18px;" src="$dir/north-mini.png" border="0"></a></div> + <div style="position: absolute; left: 4px; top: 22px; width: 18px; height: 18px;"><a href="$west"><img style="position: relative; width: 18px; height: 18px;" src="$dir/west-mini.png" border="0"></a></div> + <div style="position: absolute; left: 22px; top: 22px; width: 18px; height: 18px;"><a href="$east"><img style="position: relative; width: 18px; height: 18px;" src="$dir/east-mini.png" border="0"></a></div> + <div style="position: absolute; left: 13px; top: 40px; width: 18px; height: 18px;"><a href="$south"><img style="position: relative; width: 18px; height: 18px;" src="$dir/south-mini.png" border="0"></a></div> + <div style="position: absolute; left: 13px; top: 63px; width: 18px; height: 18px;"><a href="$zoom_in"><img style="position: relative; width: 18px; height: 18px;" src="$dir/zoom-plus-mini.png" border="0"></a></div> + <div style="position: absolute; left: 13px; top: 81px; width: 18px; height: 18px;"><a href="$world"><img style="position: relative; width: 18px; height: 18px;" src="$dir/zoom-world-mini.png" border="0"></a></div> + <div style="position: absolute; left: 13px; top: 99px; width: 18px; height: 18px;"><a href="$zoom_out"><img style="position: relative; width: 18px; height: 18px;" src="$dir/zoom-minus-mini.png" border="0"></a></div> +</div> +EOF } 1; diff --git a/perllib/FixMyStreet/Map/OSM/CycleMap.pm b/perllib/FixMyStreet/Map/OSM/CycleMap.pm index 01c51acf4..06b07ae20 100644 --- a/perllib/FixMyStreet/Map/OSM/CycleMap.pm +++ b/perllib/FixMyStreet/Map/OSM/CycleMap.pm @@ -6,66 +6,13 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::OSM::CycleMap; +use base 'FixMyStreet::Map::OSM'; use strict; -use mySociety::Web qw(ent); -sub header_js { - return ' -<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> -<script type="text/javascript" src="/js/map-OpenStreetMap.js"></script> -<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> -'; -} - -# display_map Q PARAMS -# PARAMS include: -# EASTING, NORTHING for the centre point of the map -# TYPE is 1 if the map is clickable, 2 if clickable and has a form upload, -# 0 if not clickable -# PINS is array of pins to show, location and colour -# PRE/POST are HTML to show above/below map -sub display_map { - my ($q, %params) = @_; - $params{pre} ||= ''; - $params{post} ||= ''; - - foreach my $pin (@{$params{pins}}) { - } - - my $out = FixMyStreet::Map::header($q, $params{type}); - my $copyright = _('Map © <a href="http://www.openstreetmap.org/">OpenStreetMap</a> and contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>'); - $out .= <<EOF; -<script type="text/javascript"> -var fixmystreet = { - 'easting': $params{easting}, - 'northing': $params{northing}, - 'map_type': OpenLayers.Layer.OSM.CycleMap -} -</script> -<div id="map_box"> - $params{pre} - <div id="map"></div> - <p id="copyright">$copyright</p> - $params{post} -</div> -<div id="side"> -EOF - return $out; -} - -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { +sub map_type { + return 'OpenLayers.Layer.OSM.CycleMap'; } 1; diff --git a/perllib/FixMyStreet/Map/OSM/StreetView.pm b/perllib/FixMyStreet/Map/OSM/StreetView.pm index 08f677d25..9c9a1ac8e 100644 --- a/perllib/FixMyStreet/Map/OSM/StreetView.pm +++ b/perllib/FixMyStreet/Map/OSM/StreetView.pm @@ -6,16 +6,16 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::OSM::StreetView; use strict; use mySociety::Web qw(ent); sub header_js { return ' -<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/jslib/OpenLayers-2.10/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenLayers.js"></script> <script type="text/javascript" src="/js/map-streetview.js"></script> -<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> '; } @@ -27,20 +27,27 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + my @pins; foreach my $pin (@{$params{pins}}) { + $pin->[3] ||= ''; + push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; } + my $pins_js = join(",\n", @pins); my $out = FixMyStreet::Map::header($q, $params{type}); my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); $out .= <<EOF; +<input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> <script type="text/javascript"> var fixmystreet = { - 'easting': $params{easting}, - 'northing': $params{northing} + 'latitude': $params{latitude}, + 'longitude': $params{longitude}, + 'pins': [ $pins_js ] } </script> <div id="map_box"> @@ -54,17 +61,4 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { -} - 1; diff --git a/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm b/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm index b1fe0126d..9ae5829c4 100644 --- a/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm +++ b/perllib/FixMyStreet/Map/Tilma/OL/1_10k.pm @@ -6,7 +6,7 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Tilma::OL::1_10k; use strict; @@ -18,8 +18,10 @@ use constant TILE_TYPE => '10k-full'; sub header_js { return ' -<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/jslib/OpenLayers-2.10/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenLayers.js"></script> <script type="text/javascript" src="/js/map-tilma-ol.js"></script> +<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> '; } @@ -31,12 +33,16 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + my @pins; foreach my $pin (@{$params{pins}}) { + $pin->[3] ||= ''; + push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; } + my $pins_js = join(",\n", @pins); my $out = FixMyStreet::Map::header($q, $params{type}); my $tile_width = TILE_WIDTH; @@ -44,12 +50,15 @@ sub display_map { my $sf = SCALE_FACTOR / TILE_WIDTH; my $copyright = _('© Crown copyright. All rights reserved. Ministry of Justice 100037819 2008.'); $out .= <<EOF; +<input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> <script type="text/javascript"> var fixmystreet = { 'tilewidth': $tile_width, 'tileheight': $tile_width, - 'easting': $params{easting}, - 'northing': $params{northing}, + 'latitude': $params{latitude}, + 'longitude': $params{longitude}, + 'pins': [ $pins_js ], 'tile_type': '$tile_type', 'maxResolution': $sf }; @@ -67,17 +76,4 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { -} - 1; diff --git a/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm b/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm index 7ef372351..7a898b55b 100644 --- a/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm +++ b/perllib/FixMyStreet/Map/Tilma/OL/StreetView.pm @@ -6,7 +6,7 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Tilma::OL::StreetView; use strict; @@ -18,8 +18,10 @@ use constant TILE_TYPE => 'streetview'; sub header_js { return ' -<script type="text/javascript" src="http://openlayers.org/api/OpenLayers.js"></script> +<script type="text/javascript" src="/jslib/OpenLayers-2.10/OpenLayers.js"></script> +<script type="text/javascript" src="/js/map-OpenLayers.js"></script> <script type="text/javascript" src="/js/map-tilma-ol.js"></script> +<script type="text/javascript" src="/js/OpenLayers.Projection.OrdnanceSurvey.js"></script> '; } @@ -31,12 +33,16 @@ sub header_js { # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map sub display_map { - my ($q, %params) = @_; + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; + my @pins; foreach my $pin (@{$params{pins}}) { + $pin->[3] ||= ''; + push @pins, "[ $pin->[0], $pin->[1], '$pin->[2]', '$pin->[3]' ]"; } + my $pins_js = join(",\n", @pins); my $out = FixMyStreet::Map::header($q, $params{type}); my $tile_width = TILE_WIDTH; @@ -44,12 +50,15 @@ sub display_map { my $sf = SCALE_FACTOR / TILE_WIDTH; my $copyright = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); $out .= <<EOF; +<input type="hidden" name="latitude" id="fixmystreet.latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" id="fixmystreet.longitude" value="$params{longitude}"> <script type="text/javascript"> var fixmystreet = { 'tilewidth': $tile_width, 'tileheight': $tile_width, - 'easting': $params{easting}, - 'northing': $params{northing}, + 'latitude': $params{latitude}, + 'longitude': $params{longitude}, + 'pins': [ $pins_js ], 'tile_type': '$tile_type', 'maxResolution': $sf }; @@ -65,17 +74,4 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - -sub display_pin { -} - -sub map_pins { -} - 1; diff --git a/perllib/FixMyStreet/Map/Tilma/Original.pm b/perllib/FixMyStreet/Map/Tilma/Original.pm index b6d24fd6a..0af6ed277 100644 --- a/perllib/FixMyStreet/Map/Tilma/Original.pm +++ b/perllib/FixMyStreet/Map/Tilma/Original.pm @@ -6,7 +6,7 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Tilma::Original; use strict; use LWP::Simple; @@ -16,6 +16,11 @@ use mySociety::GeoUtil; use mySociety::Locale; use mySociety::Web qw(ent NewURL); use Utils; +use RABX; + +sub TILE_WIDTH() { return $FixMyStreet::Map::map_class->tile_width; } +sub SCALE_FACTOR() { return $FixMyStreet::Map::map_class->scale_factor; } +sub TILE_TYPE() { return $FixMyStreet::Map::map_class->tile_type; } sub _ll_to_en { my ($lat, $lon) = @_; @@ -35,13 +40,13 @@ sub header_js { # 0 if not clickable # PINS is array of pins to show, location and colour # PRE/POST are HTML to show above/below map -sub _display_map { - my ($q, %params) = @_; +sub display_map { + my ($self, $q, %params) = @_; $params{pre} ||= ''; $params{post} ||= ''; my $mid_point = TILE_WIDTH; # Map is 2 TILE_WIDTHs in size, square. - if ($q->{site} eq 'barnet') { # Map is c. 380px wide - $mid_point = 189; + if (my $mp = Cobrand::tilma_mid_point(Page::get_cobrand($q))) { + $mid_point = $mp; } # convert map center point to easting, northing @@ -62,13 +67,13 @@ sub _display_map { ($input{x}) = $input{x} =~ /^(\d+)/; $input{x} ||= 0; ($input{y}) = $input{y} =~ /^(\d+)/; $input{y} ||= 0; - my ($x, $y, $px, $py) = FixMyStreet::Map::os_to_px_with_adjust($q, $params{easting}, $params{northing}, $input{x}, $input{y}); + my ($x, $y, $px, $py) = os_to_px_with_adjust($q, $params{easting}, $params{northing}, $input{x}, $input{y}); my $pins = ''; foreach my $pin (@{$params{pins}}) { - my $pin_x = FixMyStreet::Map::os_to_px($pin->[0], $x); - my $pin_y = FixMyStreet::Map::os_to_px($pin->[1], $y, 1); - $pins .= FixMyStreet::Map::display_pin($q, $pin_x, $pin_y, $pin->[2]); + my $pin_x = os_to_px($pin->[0], $x); + my $pin_y = os_to_px($pin->[1], $y, 1); + $pins .= display_pin($q, $pin_x, $pin_y, $pin->[2]); } $px = defined($px) ? $mid_point - $px : 0; @@ -98,6 +103,8 @@ sub _display_map { $out .= <<EOF; <input type="hidden" name="x" id="formX" value="$x"> <input type="hidden" name="y" id="formY" value="$y"> +<input type="hidden" name="latitude" value="$params{latitude}"> +<input type="hidden" name="longitude" value="$params{longitude}"> EOF $img_type = '<input type="image"'; } else { @@ -126,9 +133,9 @@ $params{pre} <div id="pins">$pins</div> </div> EOF - $out .= '<div id="watermark"></div>' if $params{watermark}; + $out .= '<div id="watermark"></div>' if $self->watermark(); $out .= compass($q, $x, $y); - my $copyright = $params{copyright}; + my $copyright = $self->copyright(); $out .= <<EOF; </div> <p id="copyright">$copyright</p> @@ -139,13 +146,6 @@ EOF return $out; } -sub display_map_end { - my ($type) = @_; - my $out = '</div>'; - $out .= '</form>' if ($type); - return $out; -} - sub display_pin { my ($q, $px, $py, $col, $num) = @_; $num = '' if !$num || $num > 9; @@ -156,45 +156,38 @@ sub display_pin { . 'px; left:' . ($px) . 'px; position: absolute;">'; return $out unless $_ && $_->{id} && $col ne 'blue'; my $cobrand = Page::get_cobrand($q); - my $url = Cobrand::url($cobrand, NewURL($q, -retain => 1, - -url => '/report/' . $_->{id}, - pc => undef, - x => undef, - y => undef, - sx => undef, - sy => undef, - all_pins => undef, - no_pins => undef), $q); + my $url = Cobrand::url($cobrand, NewURL($q, -url => '/report/' . $_->{id}), $q); $out = '<a title="' . ent($_->{title}) . '" href="' . $url . '">' . $out . '</a>'; return $out; } sub map_pins { - my ($q, $x, $y, $sx, $sy, $interval) = @_; + my ($self, $q, $x, $y, $sx, $sy, $interval) = @_; - my $e = FixMyStreet::Map::tile_to_os($x); - my $n = FixMyStreet::Map::tile_to_os($y); + my $e = tile_to_os($x); + my $n = tile_to_os($y); + my ( $lat, $lon ) = Utils::convert_en_to_latlon( $e, $n ); my ( $around_map, $around_map_list, $nearby, $dist ) = - FixMyStreet::Map::map_features_easting_northing( $q, $e, $n, $interval ); + FixMyStreet::Map::map_features( $q, $lat, $lon, $interval ); my $pins = ''; foreach (@$around_map) { ( $_->{easting}, $_->{northing} ) = _ll_to_en( $_->{latitude}, $_->{longitude} ); - my $px = FixMyStreet::Map::os_to_px($_->{easting}, $sx); - my $py = FixMyStreet::Map::os_to_px($_->{northing}, $sy, 1); + my $px = os_to_px($_->{easting}, $sx); + my $py = os_to_px($_->{northing}, $sy, 1); my $col = $_->{state} eq 'fixed' ? 'green' : 'red'; - $pins .= FixMyStreet::Map::display_pin($q, $px, $py, $col); + $pins .= display_pin($q, $px, $py, $col); } foreach (@$nearby) { ( $_->{easting}, $_->{northing} ) = _ll_to_en( $_->{latitude}, $_->{longitude} ); - my $px = FixMyStreet::Map::os_to_px($_->{easting}, $sx); - my $py = FixMyStreet::Map::os_to_px($_->{northing}, $sy, 1); + my $px = os_to_px($_->{easting}, $sx); + my $py = os_to_px($_->{northing}, $sy, 1); my $col = $_->{state} eq 'fixed' ? 'green' : 'red'; - $pins .= FixMyStreet::Map::display_pin($q, $px, $py, $col); + $pins .= display_pin($q, $px, $py, $col); } return ($pins, $around_map_list, $nearby, $dist); @@ -236,7 +229,7 @@ Takes the tile x,y and converts to lat, lon. =cut sub tile_xy_to_wgs84 { - my ( $x, $y ) = @_; + my ( $self, $x, $y ) = @_; my $easting = tile_to_os($x); my $northing = tile_to_os($y); @@ -258,17 +251,19 @@ sub click_to_tile { # tile they were), convert to OSGB36 and return. sub click_to_os { my ($pin_tile_x, $pin_x, $pin_tile_y, $pin_y) = @_; - my $tile_x = FixMyStreet::Map::click_to_tile($pin_tile_x, $pin_x); - my $tile_y = FixMyStreet::Map::click_to_tile($pin_tile_y, $pin_y, 1); - my $easting = FixMyStreet::Map::tile_to_os($tile_x); - my $northing = FixMyStreet::Map::tile_to_os($tile_y); + my $tile_x = click_to_tile($pin_tile_x, $pin_x); + my $tile_y = click_to_tile($pin_tile_y, $pin_y, 1); + my $easting = tile_to_os($tile_x); + my $northing = tile_to_os($tile_y); return ($easting, $northing); } # Given some click co-ords (the tile they were on, and where in the # tile they were), convert to WGS84 and return. sub click_to_wgs84 { - my ( $easting, $northing ) = FixMyStreet::Map::click_to_os(@_); + my $self = shift; + my $q = shift; + my ( $easting, $northing ) = click_to_os(@_); my ( $lat, $lon ) = mySociety::GeoUtil::national_grid_to_wgs84( $easting, $northing, 'G' ); return ( $lat, $lon ); } @@ -279,8 +274,8 @@ sub click_to_wgs84 { sub os_to_px_with_adjust { my ($q, $easting, $northing, $in_x, $in_y) = @_; - my $x = FixMyStreet::Map::os_to_tile($easting); - my $y = FixMyStreet::Map::os_to_tile($northing); + my $x = os_to_tile($easting); + my $y = os_to_tile($northing); my $x_tile = $in_x || int($x); my $y_tile = $in_y || int($y); @@ -292,20 +287,51 @@ sub os_to_px_with_adjust { $y_tile += 1; } - my $px = FixMyStreet::Map::os_to_px($easting, $x_tile); - my $py = FixMyStreet::Map::os_to_px($northing, $y_tile, 1); + my $px = os_to_px($easting, $x_tile); + my $py = os_to_px($northing, $y_tile, 1); if ($q->{site} eq 'barnet') { # Map is 380px, so might need to adjust if (!$in_x && $px > 380) { $x_tile++; - $px = FixMyStreet::Map::os_to_px($easting, $x_tile); + $px = os_to_px($easting, $x_tile); } if (!$in_y && $py > 380) { $y_tile--; - $py = FixMyStreet::Map::os_to_px($northing, $y_tile, 1); + $py = os_to_px($northing, $y_tile, 1); } } return ($x_tile, $y_tile, $px, $py); } +sub compass ($$$) { + my ( $q, $x, $y ) = @_; + my @compass; + for ( my $i = $x - 1 ; $i <= $x + 1 ; $i++ ) { + for ( my $j = $y - 1 ; $j <= $y + 1 ; $j++ ) { + $compass[$i][$j] = NewURL( $q, x => $i, y => $j ); + } + } + my $recentre = NewURL($q); + my $host = Page::base_url_with_lang( $q, undef ); + return <<EOF; +<table cellpadding="0" cellspacing="0" border="0" id="compass"> +<tr valign="bottom"> +<td align="right"><a rel="nofollow" href="${compass[$x-1][$y+1]}"><img src="$host/i/arrow-northwest.gif" alt="NW" width=11 height=11></a></td> +<td align="center"><a rel="nofollow" href="${compass[$x][$y+1]}"><img src="$host/i/arrow-north.gif" vspace="3" alt="N" width=13 height=11></a></td> +<td><a rel="nofollow" href="${compass[$x+1][$y+1]}"><img src="$host/i/arrow-northeast.gif" alt="NE" width=11 height=11></a></td> +</tr> +<tr> +<td><a rel="nofollow" href="${compass[$x-1][$y]}"><img src="$host/i/arrow-west.gif" hspace="3" alt="W" width=11 height=13></a></td> +<td align="center"><a rel="nofollow" href="$recentre"><img src="$host/i/rose.gif" alt="Recentre" width=35 height=34></a></td> +<td><a rel="nofollow" href="${compass[$x+1][$y]}"><img src="$host/i/arrow-east.gif" hspace="3" alt="E" width=11 height=13></a></td> +</tr> +<tr valign="top"> +<td align="right"><a rel="nofollow" href="${compass[$x-1][$y-1]}"><img src="$host/i/arrow-southwest.gif" alt="SW" width=11 height=11></a></td> +<td align="center"><a rel="nofollow" href="${compass[$x][$y-1]}"><img src="$host/i/arrow-south.gif" vspace="3" alt="S" width=13 height=11></a></td> +<td><a rel="nofollow" href="${compass[$x+1][$y-1]}"><img src="$host/i/arrow-southeast.gif" alt="SE" width=11 height=11></a></td> +</tr> +</table> +EOF +} + 1; diff --git a/perllib/FixMyStreet/Map/Tilma/Original/1_10k.pm b/perllib/FixMyStreet/Map/Tilma/Original/1_10k.pm index f97163c68..722df2a46 100644 --- a/perllib/FixMyStreet/Map/Tilma/Original/1_10k.pm +++ b/perllib/FixMyStreet/Map/Tilma/Original/1_10k.pm @@ -6,23 +6,23 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Tilma::Original::1_10k; +use base 'FixMyStreet::Map::Tilma::Original'; use strict; -use constant TILE_WIDTH => 254; -use constant TIF_SIZE_M => 5000; -use constant TIF_SIZE_PX => 7874; -use constant SCALE_FACTOR => TIF_SIZE_M / (TIF_SIZE_PX / TILE_WIDTH); -use constant TILE_TYPE => '10k-full'; +sub tile_width { return 254; } +sub tif_size_m { return 5000; } +sub tif_size_px { return 7874; } +sub scale_factor { return tif_size_m() / (tif_size_px() / tile_width()); } +sub tile_type { return '10k-full'; } -use FixMyStreet::Map::Tilma::Original; +sub copyright { + return _('© Crown copyright. All rights reserved. Ministry of Justice 100037819 2008.'); +} -sub display_map { - my ($q, %params) = @_; - $params{copyright} = _('© Crown copyright. All rights reserved. Ministry of Justice 100037819 2008.'); - $params{watermark} = 1; - return _display_map($q, %params); +sub watermark { + return 1; } 1; diff --git a/perllib/FixMyStreet/Map/Tilma/Original/StreetView.pm b/perllib/FixMyStreet/Map/Tilma/Original/StreetView.pm index 103f4c15c..fe03fdb00 100644 --- a/perllib/FixMyStreet/Map/Tilma/Original/StreetView.pm +++ b/perllib/FixMyStreet/Map/Tilma/Original/StreetView.pm @@ -6,22 +6,23 @@ # Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved. # Email: matthew@mysociety.org; WWW: http://www.mysociety.org/ -package FixMyStreet::Map; +package FixMyStreet::Map::Tilma::Original::StreetView; +use base 'FixMyStreet::Map::Tilma::Original'; use strict; -use constant TILE_WIDTH => 250; -use constant TIF_SIZE_M => 5000; -use constant TIF_SIZE_PX => 5000; -use constant SCALE_FACTOR => TIF_SIZE_M / (TIF_SIZE_PX / TILE_WIDTH); -use constant TILE_TYPE => 'streetview'; +sub tile_width { return 250; } +sub tif_size_m { return 5000; } +sub tif_size_px { return 5000; } +sub scale_factor { return tif_size_m() / (tif_size_px() / tile_width()); } +sub tile_type { return 'streetview'; } -use FixMyStreet::Map::Tilma::Original; +sub copyright { + return _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); +} -sub display_map { - my ($q, %params) = @_; - $params{copyright} = _('Map contains Ordnance Survey data © Crown copyright and database right 2010.'); - return _display_map($q, %params); +sub watermark { + return 0; } 1; diff --git a/perllib/Page.pm b/perllib/Page.pm index 9819a6e80..797da363d 100644 --- a/perllib/Page.pm +++ b/perllib/Page.pm @@ -21,6 +21,7 @@ use File::Slurp; use HTTP::Date; # time2str use Image::Magick; use Image::Size; +use IO::String; use POSIX qw(strftime); use URI::Escape; use Text::Template; @@ -52,15 +53,17 @@ my $lastmodified; sub do_fastcgi { my ($func, $lm, $binary) = @_; - binmode(STDOUT, ":utf8") unless $binary; - try { my $W = new mySociety::WatchUpdate(); while (my $q = new mySociety::Web(unicode => 1)) { next if $lm && $q->Maybe304($lm); $lastmodified = $lm; microsite($q); + my $str_fh = IO::String->new; + my $old_fh = select($str_fh); &$func($q); + select($old_fh) if defined $old_fh; + print $binary ? ${$str_fh->string_ref} : encode_utf8(${$str_fh->string_ref}); dbh()->rollback() if $mySociety::DBHandle::conf_ok; $W->exit_if_changed(); } @@ -116,6 +119,8 @@ sub microsite { $lang = 'en-gb' if $host =~ /^en\./; Cobrand::set_lang_and_domain(get_cobrand($q), $lang, 1); + FixMyStreet::Map::set_map_class($q->param('map')); + Problems::set_site_restriction($q); Memcached::set_namespace(mySociety::Config::get('BCI_DB_NAME') . ":"); } @@ -254,7 +259,9 @@ sub template_include { return undef unless -e $template_file; $template = Text::Template->new( - SOURCE => $template_file, + TYPE => 'STRING', + # Don't use FILE, because we need to make sure it's Unicode characters + SOURCE => decode_utf8(File::Slurp::read_file($template_file)), DELIMITERS => ['{{', '}}'], ); return $template->fill_in(HASH => \%params); @@ -385,12 +392,10 @@ sub error_page ($$) { } # send_email TO (NAME) TEMPLATE-NAME PARAMETERS -# TEMPLATE-NAME is currently one of problem, update, alert, tms +# TEMPLATE-NAME is a full filename here. sub send_email { - my ($q, $recipient_email_address, $name, $thing, %h) = @_; - my $file_thing = $thing; - $file_thing = 'empty property' if $q->{site} eq 'emptyhomes' && $thing eq 'problem'; # Needs to be in English - my $template = "$file_thing-confirm"; + my ($q, $recipient_email_address, $name, $template, %h) = @_; + $template = File::Slurp::read_file("$FindBin::Bin/../templates/emails/$template"); my $to = $name ? [[$recipient_email_address, $name]] : $recipient_email_address; my $cobrand = get_cobrand($q); @@ -438,6 +443,19 @@ sub send_email { ); } +} + +# send_confirmation_email TO (NAME) TEMPLATE-NAME PARAMETERS +# TEMPLATE-NAME is currently one of problem, update, alert, tms +sub send_confirmation_email { + my ($q, $recipient_email_address, $name, $thing, %h) = @_; + + my $file_thing = $thing; + $file_thing = 'empty property' if $q->{site} eq 'emptyhomes' && $thing eq 'problem'; # Needs to be in English + my $template = "$file_thing-confirm"; + + send_email($q, $recipient_email_address, $name, $template, %h); + my ($action, $worry); if ($thing eq 'problem') { $action = _('your problem will not be posted'); @@ -462,6 +480,7 @@ if you do not, %s.</p> <p>(Don't worry — %s)</p> EOF + my $cobrand = get_cobrand($q); my %vars = ( action => $action, worry => $worry, @@ -536,17 +555,17 @@ sub display_problem_meta_line($$) { $out .= sprintf(_('%s, reported by %s at %s'), ent($category), ent($problem->{name}), $date_time); } } else { - if ($problem->{service} && $problem->{category} && $problem->{category} ne 'Other' && $problem->{anonymous}) { + if ($problem->{service} && $problem->{category} && $problem->{category} ne _('Other') && $problem->{anonymous}) { $out .= sprintf(_('Reported by %s in the %s category anonymously at %s'), ent($problem->{service}), ent($problem->{category}), $date_time); - } elsif ($problem->{service} && $problem->{category} && $problem->{category} ne 'Other') { + } elsif ($problem->{service} && $problem->{category} && $problem->{category} ne _('Other')) { $out .= sprintf(_('Reported by %s in the %s category by %s at %s'), ent($problem->{service}), ent($problem->{category}), ent($problem->{name}), $date_time); } elsif ($problem->{service} && $problem->{anonymous}) { $out .= sprintf(_('Reported by %s anonymously at %s'), ent($problem->{service}), $date_time); } elsif ($problem->{service}) { $out .= sprintf(_('Reported by %s by %s at %s'), ent($problem->{service}), ent($problem->{name}), $date_time); - } elsif ($problem->{category} && $problem->{category} ne 'Other' && $problem->{anonymous}) { + } elsif ($problem->{category} && $problem->{category} ne _('Other') && $problem->{anonymous}) { $out .= sprintf(_('Reported in the %s category anonymously at %s'), ent($problem->{category}), $date_time); - } elsif ($problem->{category} && $problem->{category} ne 'Other') { + } elsif ($problem->{category} && $problem->{category} ne _('Other')) { $out .= sprintf(_('Reported in the %s category by %s at %s'), ent($problem->{category}), ent($problem->{name}), $date_time); } elsif ($problem->{anonymous}) { $out .= sprintf(_('Reported anonymously at %s'), $date_time); @@ -667,12 +686,14 @@ sub mapit_check_error { return _('That postcode was not recognised, sorry.') if $location->{code} =~ /^4/; return $location->{error}; } - my $island = $location->{coordsyst}; - if (!$island) { - return _("Sorry, that appears to be a Crown dependency postcode, which we don't cover."); - } - if ($island eq 'I') { - return _("We do not cover Northern Ireland, I'm afraid, as our licence doesn't include any maps for the region."); + if (mySociety::Config::get('COUNTRY') eq 'GB') { + my $island = $location->{coordsyst}; + if (!$island) { + return _("Sorry, that appears to be a Crown dependency postcode, which we don't cover."); + } + if ($island eq 'I') { + return _("We do not cover Northern Ireland, I'm afraid, as our licence doesn't include any maps for the region."); + } } return 0; } |