summaryrefslogtreecommitdiff
path: root/httemplate/search
diff options
context:
space:
mode:
authorMark Wells <mark@freeside.biz>2016-03-12 18:59:05 -0800
committerMark Wells <mark@freeside.biz>2016-03-20 16:42:01 -0700
commit14d83a8b09462027016c0ea3511b8d54b1f2519a (patch)
treeb6035b4265831b2753032b50f5197fc4bcb386a7 /httemplate/search
parent9ed4d732a91d71a024d1c469730c737f64fa848a (diff)
show map of svc_broadband and tower locations, #37802
Diffstat (limited to 'httemplate/search')
-rw-r--r--httemplate/search/elements/gmap.html123
-rwxr-xr-xhttemplate/search/svc_broadband-map.html178
-rwxr-xr-xhttemplate/search/svc_broadband.cgi4
3 files changed, 305 insertions, 0 deletions
diff --git a/httemplate/search/elements/gmap.html b/httemplate/search/elements/gmap.html
new file mode 100644
index 000000000..8b070ebf9
--- /dev/null
+++ b/httemplate/search/elements/gmap.html
@@ -0,0 +1,123 @@
+<%args>
+@features
+</%args>
+<%doc>
+Generic Google Maps front end.
+
+<& /elements/gmap.html,
+ features => [
+ { id => 'svc_acct/12',
+ geometry => {
+ type => 'Point',
+ coordinates => [ -86, 40 ], # optionally altitude as the third coord
+ },
+ properties => {
+ # see https://developers.google.com/maps/documentation/javascript/3.exp/reference#Data.StyleOptions
+ style => {
+ icon => {
+ scale => 4,
+ fillColor => 'orange',
+ }
+ },
+ # content of popup info box (might AJAX this later)
+ content => '<a href="view/svc_acct.cgi?12">username@example.com</a>',
+ }
+ }, # end of feature
+ ],
+&>
+
+</%doc>
+<%init>
+foreach (@features) {
+ $_->{type} = 'Feature';
+ # any other per-feature massaging can go here
+}
+my $tree = {
+ type => 'FeatureCollection',
+ features => \@features
+};
+
+</%init>
+<div id="map_canvas"></div>
+
+<style type="text/css">
+html { height: 100% }
+
+body { height: 100%; margin: 0px; padding: 0px }
+
+#map_canvas { height: 100%; }
+</style>
+
+<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3">
+</script>
+
+<script type="text/javascript">
+
+var data_geojson = <% encode_json($tree) %>;
+
+var baseStyle = {
+ clickable: true,
+ icon: {
+ path: google.maps.SymbolPath.CIRCLE,
+ scale: 4,
+ fillColor: 'green',
+ fillOpacity: 1,
+ strokeColor: 'black',
+ strokeWeight: 1,
+ },
+};
+
+var featureStyle = function(feature) {
+ // jQuery.extend(): merge properties of objects
+ // 'true' makes it a deep copy; start the merge with {} so that
+ // baseStyle doesn't get overwritten
+ return $.extend(true, {}, baseStyle, feature.getProperty('style'));
+};
+
+var map;
+function initMap() {
+ var canvas = $('#map_canvas');
+ map = new google.maps.Map(canvas[0], { zoom: 6 });
+ try {
+ map.data.addGeoJson(data_geojson);
+ } catch(ex) {
+ console.log(ex.toString);
+ debugger;
+ }
+
+ // construct bounds around all of the features
+ var bounds = new google.maps.LatLngBounds;
+ map.data.forEach(function(feature) {
+ var g = feature.getGeometry();
+ if (g.getType() == 'Point') {
+ bounds.extend(g.get());
+ } else if (g.getArray) {
+ g.getArray().forEach(function(point) { bounds.extend(point); });
+ }
+ });
+
+ map.fitBounds(bounds);
+ map.data.setStyle(featureStyle);
+
+ var info = new google.maps.InfoWindow;
+ map.data.addListener('click', function(ev) {
+ var feature = ev.feature;
+ if ( feature.getGeometry().getType() == 'Point' ) {
+ // then pop up an info box with the feature content
+ info.close();
+ info.setPosition(feature.getGeometry().get());
+ info.setContent(feature.getProperty('content'));
+ info.open(map);
+ }
+
+ // snap to feature ROI if it has one
+ if ( feature.getProperty('bounds') ) {
+ map.fitBounds( feature.getProperty('bounds') );
+ }
+
+ }); // addListener()
+}
+
+$().ready( initMap );
+</script>
+
diff --git a/httemplate/search/svc_broadband-map.html b/httemplate/search/svc_broadband-map.html
new file mode 100755
index 000000000..4c660b016
--- /dev/null
+++ b/httemplate/search/svc_broadband-map.html
@@ -0,0 +1,178 @@
+<& /elements/header.html, 'Broadband Search Results' &>
+
+<& elements/gmap.html, features => \@features &>
+
+<& /elements/footer.html &>
+<%init>
+
+die "access denied" unless
+ $FS::CurrentUser::CurrentUser->access_right('List services');
+
+my $conf = new FS::Conf;
+
+my @features; # geoJSON structure
+
+# accept all the search logic from svc_broadband.cgi...
+my %search_hash;
+if ( $cgi->param('magic') eq 'unlinked' ) {
+ %search_hash = ( 'unlinked' => 1 );
+} else {
+ foreach (qw( custnum agentnum svcpart cust_fields )) {
+ $search_hash{$_} = $cgi->param($_) if $cgi->param($_);
+ }
+ foreach (qw(pkgpart routernum towernum sectornum)) {
+ $search_hash{$_} = [ $cgi->param($_) ] if $cgi->param($_);
+ }
+}
+
+if ( $cgi->param('sortby') =~ /^(\w+)$/ ) {
+ $search_hash{'order_by'} = "ORDER BY $1";
+}
+
+my $sql_query = FS::svc_broadband->search(\%search_hash);
+
+my %routerbyblock = ();
+
+my @rows = qsearch($sql_query);
+my %sectors;
+my %towers;
+my %tower_coord;
+my %tower_bounds;
+foreach my $svc_broadband (@rows) {
+ # don't try to show it if coords aren't set
+ next if !$svc_broadband->latitude || !$svc_broadband->longitude;
+ # coerce coordinates to numbers
+ my @coord = (
+ $svc_broadband->longitude + 0,
+ $svc_broadband->latitude + 0,
+ );
+ push @coord, $svc_broadband->altitude + 0
+ if length($svc_broadband->altitude); # it's optional
+
+ push @features,
+ {
+ id => 'svc_broadband/'.$svc_broadband->svcnum,
+ geometry => {
+ type => 'Point',
+ coordinates => \@coord,
+ },
+ properties => {
+ content => include('.svc_broadband', $svc_broadband),
+ },
+ };
+ # look up tower location and draw connecting line
+ next if !$svc_broadband->sectornum;
+ my $sector = $sectors{$svc_broadband->sectornum} ||= $svc_broadband->tower_sector;
+ my $towernum = $sector->towernum;
+ my $tower = $towers{$towernum};
+
+ if (!$tower) {
+ $tower = $towers{$towernum} = $sector->tower;
+ $tower_coord{$towernum} =
+ [ $tower->longitude + 0,
+ $tower->latitude + 0,
+ ($tower->altitude || 0) + 0,
+ ];
+
+ }
+
+ my $tower = $towers{$towernum};
+ if ( $tower->latitude and $tower->longitude ) {
+ push @features,
+ {
+ geometry => {
+ type => 'LineString',
+ coordinates => [ \@coord, $tower_coord{$towernum} ],
+ },
+ properties => {
+ style => {
+ strokeColor => ($tower->color || 'green'),
+ strokeWeight => 2,
+ },
+ },
+ };
+
+ # also extend tower's ROI to include this point
+ # (this is experimental; might get better results using the centroid of
+ # all connected services or something)
+ my $bounds = $tower_bounds{$towernum} ||= {
+ east => $tower->longitude,
+ west => $tower->longitude,
+ north => $tower->latitude,
+ south => $tower->latitude,
+ };
+ if ($coord[0] > $bounds->{east}) {
+ $bounds->{east} = $coord[0];
+ } elsif ($coord[0] < $bounds->{west}) {
+ $bounds->{west} = $coord[0];
+ }
+ if ($coord[1] > $bounds->{north}) {
+ $bounds->{north} = $coord[1]
+ } elsif ($coord[1] < $bounds->{south}) {
+ $bounds->{south} = $coord[1]
+ }
+
+ } # if tower has coords
+} # foreach $svc_broadband
+
+foreach my $tower (values(%towers)) {
+ my $towernum = $tower->towernum;
+ my $bounds = $tower_bounds{$towernum};
+ # add some padding for easier reading
+ my $dx = 0.1 * ($bounds->{east} - $bounds->{west});
+ my $dy = 0.1 * ($bounds->{north} - $bounds->{south});
+ $bounds->{east} += $dx;
+ $bounds->{west} -= $dx;
+ $bounds->{north} += $dy;
+ $bounds->{south} -= $dy;
+ push @features,
+ {
+ id => 'tower/'.$towernum,
+ geometry => {
+ type => 'Point',
+ coordinates => $tower_coord{$towernum},
+ },
+ properties => {
+ style => {
+ icon => {
+ path => undef,
+ url => $fsurl.'images/jcartier-antenna-square-21x51.png',
+ anchor => { x => 10, y => 4 }
+ },
+ },
+ content => include('.tower', $tower),
+ bounds => $tower_bounds{$towernum},
+ },
+ };
+}
+
+</%init>
+<%def .svc_broadband>
+% my $svc = shift;
+% my @label = $svc->cust_svc->label;
+<H3>
+ <a target="_blank" href="<% $fsurl %>view/svc_broadband.cgi?<% $svc->svcnum %>">
+ <% $label[0] |h %> #<% $svc->svcnum %> | <% $label[1] %>
+ </a>
+</H3>
+% my $cust_main = $svc->cust_main;
+<a target="_blank" href="<% $fsurl %>view/cust_main.cgi?<% $cust_main->custnum %>">
+<& /elements/small_custview.html, {
+ cust_main => $svc->cust_main,
+ #url => $fsurl.'view/cust_main.cgi',
+} &>
+</a>
+</%def>
+<%def .tower>
+% my $tower = shift;
+% my $can_edit = $FS::CurrentUser::CurrentUser->access_right('Configuration');
+<H3>
+% if ( $can_edit ) {
+ <a target="_blank" href="<% $fsurl %>edit/tower.html?<% $tower->towernum %>">
+% }
+Tower #<% $tower->towernum %> | <% $tower->towername %>
+% if ( $can_edit ) {
+ </a>
+% }
+</H3>
+</%def>
diff --git a/httemplate/search/svc_broadband.cgi b/httemplate/search/svc_broadband.cgi
index 856197725..6bf4f0850 100755
--- a/httemplate/search/svc_broadband.cgi
+++ b/httemplate/search/svc_broadband.cgi
@@ -105,5 +105,9 @@ my $html_init = include('/elements/email-link.html',
'search_hash' => \%search_hash,
'table' => 'svc_broadband'
);
+$html_init .= ' | ' .
+ '<a href="' .
+ $fsurl . 'search/svc_broadband-map.html?' . $cgi->query_string .
+ '">' . emt('View a map of these services') . '</a>';
</%init>