From: Mark Wells Date: Wed, 5 Oct 2016 21:06:32 +0000 (-0700) Subject: map selection of tower site X-Git-Url: http://git.freeside.biz/gitweb/?p=freeside.git;a=commitdiff_plain;h=07a1441c0fbce0a6ec76c7821e440444b4aec4f8 map selection of tower site --- diff --git a/httemplate/browse/tower.html b/httemplate/browse/tower.html index 16e44c6c0..555b8a39f 100644 --- a/httemplate/browse/tower.html +++ b/httemplate/browse/tower.html @@ -3,8 +3,10 @@ 'name' => 'towers', 'menubar' => [ 'Add a new tower' => $p.'edit/tower.html', - 'Sector coverage maps' => - $p.'search/sector.html', + #'Sector coverage maps' => + # $p.'search/sector.html', + 'Tower map' => + $p.'search/tower-map.html', 'Download CSV for towercoverage.com' => $p.'misc/tower-export.html?format=tc' ], diff --git a/httemplate/docs/license.html b/httemplate/docs/license.html index e5e3eab65..0f0a3c61d 100644 --- a/httemplate/docs/license.html +++ b/httemplate/docs/license.html @@ -134,6 +134,10 @@ under the terms of the MIT license. Contains the XRegExp library by Steven Levithan, licensed under the terms of the MIT license. +

+Contains the Google Maps Longitude and Latitude Picker, by Richard Dancsi, +licensed under the terms of the MIT license. +

diff --git a/httemplate/edit/tower.html b/httemplate/edit/tower.html index dae5d5a89..946a1405e 100644 --- a/httemplate/edit/tower.html +++ b/httemplate/edit/tower.html @@ -2,6 +2,7 @@ name_singular => 'tower', table => 'tower', viewall_dir => 'browse', + html_init => include('/elements/mapselect.html'), fields => [ 'towername', { field=>'disabled', type=>'checkbox', value=>'Y', }, { field=>'color', type=>'pickcolor' }, diff --git a/httemplate/elements/jquery-gmaps-latlon-picker.js b/httemplate/elements/jquery-gmaps-latlon-picker.js new file mode 100644 index 000000000..b839df75a --- /dev/null +++ b/httemplate/elements/jquery-gmaps-latlon-picker.js @@ -0,0 +1,254 @@ +/** + * + * A JQUERY GOOGLE MAPS LATITUDE AND LONGITUDE LOCATION PICKER + * version 1.2 + * + * Supports multiple maps. Works on touchscreen. Easy to customize markup and CSS. + * + * To see a live demo, go to: + * http://www.wimagguc.com/projects/jquery-latitude-longitude-picker-gmaps/ + * + * by Richard Dancsi + * http://www.wimagguc.com/ + * + */ + +(function($) { + +// for ie9 doesn't support debug console >>> +if (!window.console) window.console = {}; +if (!window.console.log) window.console.log = function () { }; +// ^^^ + +/* local modification */ +window.gMapsLatLonPickerState = {}; + +$.fn.gMapsLatLonPicker = (function() { + + var _self = this; + + /////////////////////////////////////////////////////////////////////////////////////////////// + // PARAMETERS (MODIFY THIS PART) ////////////////////////////////////////////////////////////// + _self.params = { + defLat : 0, + defLng : 0, + defZoom : 1, + queryLocationNameWhenLatLngChanges: true, + queryElevationWhenLatLngChanges: true, + mapOptions : { + mapTypeId: google.maps.MapTypeId.ROADMAP, + /* local modification */ + //mapTypeControl: false, + disableDoubleClickZoom: true, + zoomControlOptions: true, + streetViewControl: false + }, + strings : { + markerText : "Drag this Marker", + error_empty_field : "Couldn't find coordinates for this place", + error_no_results : "Couldn't find coordinates for this place" + } + }; + + + /////////////////////////////////////////////////////////////////////////////////////////////// + // VARIABLES USED BY THE FUNCTION (DON'T MODIFY THIS PART) //////////////////////////////////// + _self.vars = { + ID : null, + LATLNG : null, + map : null, + marker : null, + geocoder : null + }; + + /////////////////////////////////////////////////////////////////////////////////////////////// + // PRIVATE FUNCTIONS FOR MANIPULATING DATA //////////////////////////////////////////////////// + var setPosition = function(position) { + _self.vars.marker.setPosition(position); + _self.vars.map.panTo(position); + + $(_self.vars.cssID + ".gllpZoom").val( _self.vars.map.getZoom() ); + $(_self.vars.cssID + ".gllpLongitude").val( position.lng() ); + $(_self.vars.cssID + ".gllpLatitude").val( position.lat() ); + + $(_self.vars.cssID).trigger("location_changed", $(_self.vars.cssID)); + + if (_self.params.queryLocationNameWhenLatLngChanges) { + getLocationName(position); + } + if (_self.params.queryElevationWhenLatLngChanges) { + getElevation(position); + } + }; + + // for reverse geocoding + var getLocationName = function(position) { + var latlng = new google.maps.LatLng(position.lat(), position.lng()); + _self.vars.geocoder.geocode({'latLng': latlng}, function(results, status) { + if (status == google.maps.GeocoderStatus.OK && results[1]) { + $(_self.vars.cssID + ".gllpLocationName").val(results[1].formatted_address); + } else { + $(_self.vars.cssID + ".gllpLocationName").val(""); + } + $(_self.vars.cssID).trigger("location_name_changed", $(_self.vars.cssID)); + }); + }; + + // for getting the elevation value for a position + var getElevation = function(position) { + var latlng = new google.maps.LatLng(position.lat(), position.lng()); + + var locations = [latlng]; + + var positionalRequest = { 'locations': locations }; + + _self.vars.elevator.getElevationForLocations(positionalRequest, function(results, status) { + if (status == google.maps.ElevationStatus.OK) { + if (results[0]) { + $(_self.vars.cssID + ".gllpElevation").val( results[0].elevation.toFixed(3)); + } else { + $(_self.vars.cssID + ".gllpElevation").val(""); + } + } else { + $(_self.vars.cssID + ".gllpElevation").val(""); + } + $(_self.vars.cssID).trigger("elevation_changed", $(_self.vars.cssID)); + }); + }; + + // search function + var performSearch = function(string, silent) { + if (string == "") { + if (!silent) { + displayError( _self.params.strings.error_empty_field ); + } + return; + } + _self.vars.geocoder.geocode( + {"address": string}, + function(results, status) { + if (status == google.maps.GeocoderStatus.OK) { + $(_self.vars.cssID + ".gllpZoom").val(11); + _self.vars.map.setZoom( parseInt($(_self.vars.cssID + ".gllpZoom").val()) ); + setPosition( results[0].geometry.location ); + } else { + if (!silent) { + displayError( _self.params.strings.error_no_results ); + } + } + } + ); + }; + + // error function + var displayError = function(message) { + alert(message); + }; + + /////////////////////////////////////////////////////////////////////////////////////////////// + // PUBLIC FUNCTIONS ////////////////////////////////////////////////////////////////////////// + var publicfunc = { + + // INITIALIZE MAP ON DIV ////////////////////////////////////////////////////////////////// + init : function(object) { + + if ( !$(object).attr("id") ) { + if ( $(object).attr("name") ) { + $(object).attr("id", $(object).attr("name") ); + } else { + $(object).attr("id", "_MAP_" + Math.ceil(Math.random() * 10000) ); + } + } + + _self.vars.ID = $(object).attr("id"); + _self.vars.cssID = "#" + _self.vars.ID + " "; + + _self.params.defLat = $(_self.vars.cssID + ".gllpLatitude").val() ? $(_self.vars.cssID + ".gllpLatitude").val() : _self.params.defLat; + _self.params.defLng = $(_self.vars.cssID + ".gllpLongitude").val() ? $(_self.vars.cssID + ".gllpLongitude").val() : _self.params.defLng; + _self.params.defZoom = $(_self.vars.cssID + ".gllpZoom").val() ? parseInt($(_self.vars.cssID + ".gllpZoom").val()) : _self.params.defZoom; + + _self.vars.LATLNG = new google.maps.LatLng(_self.params.defLat, _self.params.defLng); + + _self.vars.MAPOPTIONS = _self.params.mapOptions; + _self.vars.MAPOPTIONS.zoom = _self.params.defZoom; + _self.vars.MAPOPTIONS.center = _self.vars.LATLNG; + + _self.vars.map = new google.maps.Map($(_self.vars.cssID + ".gllpMap").get(0), _self.vars.MAPOPTIONS); + _self.vars.geocoder = new google.maps.Geocoder(); + _self.vars.elevator = new google.maps.ElevationService(); + + _self.vars.marker = new google.maps.Marker({ + position: _self.vars.LATLNG, + map: _self.vars.map, + title: _self.params.strings.markerText, + draggable: true + }); + + // Set position on doubleclick + google.maps.event.addListener(_self.vars.map, 'dblclick', function(event) { + setPosition(event.latLng); + }); + + // Set position on marker move + google.maps.event.addListener(_self.vars.marker, 'dragend', function(event) { + setPosition(_self.vars.marker.position); + }); + + // Set zoom feld's value when user changes zoom on the map + google.maps.event.addListener(_self.vars.map, 'zoom_changed', function(event) { + $(_self.vars.cssID + ".gllpZoom").val( _self.vars.map.getZoom() ); + $(_self.vars.cssID).trigger("location_changed", $(_self.vars.cssID)); + }); + + // Update location and zoom values based on input field's value + $(_self.vars.cssID + ".gllpUpdateButton").bind("click", function() { + var lat = $(_self.vars.cssID + ".gllpLatitude").val(); + var lng = $(_self.vars.cssID + ".gllpLongitude").val(); + var latlng = new google.maps.LatLng(lat, lng); + _self.vars.map.setZoom( parseInt( $(_self.vars.cssID + ".gllpZoom").val() ) ); + setPosition(latlng); + }); + + // Search function by search button + $(_self.vars.cssID + ".gllpSearchButton").bind("click", function() { + performSearch( $(_self.vars.cssID + ".gllpSearchField").val(), false ); + }); + + // Search function by gllp_perform_search listener + $(document).bind("gllp_perform_search", function(event, object) { + performSearch( $(object).attr('string'), true ); + }); + + // Zoom function triggered by gllp_perform_zoom listener + $(document).bind("gllp_update_fields", function(event) { + var lat = $(_self.vars.cssID + ".gllpLatitude").val(); + var lng = $(_self.vars.cssID + ".gllpLongitude").val(); + var latlng = new google.maps.LatLng(lat, lng); + _self.vars.map.setZoom( parseInt( $(_self.vars.cssID + ".gllpZoom").val() ) ); + setPosition(latlng); + }); + + /* local modification */ + window.gMapsLatLonPickerState[_self.vars.ID] = + { + vars : _self.vars, + params : _self.params + }; + } // publicfunc + + } + + return publicfunc; +}); + +}(jQuery)); + +$(document).ready( function() { + $(".gllpLatlonPicker").each(function() { + $(document).gMapsLatLonPicker().init( $(this) ); + }); +}); + +$(document).bind("location_changed", function(event, object) { + console.log("changed: " + $(object).attr('id') ); +}); diff --git a/httemplate/elements/mapselect.html b/httemplate/elements/mapselect.html new file mode 100644 index 000000000..7d1447f98 --- /dev/null +++ b/httemplate/elements/mapselect.html @@ -0,0 +1,72 @@ +<%init> +my $conf = new FS::Conf; +my $apikey = $conf->config('google_maps_api_key'); + +my %opt = @_; + +# Currently requires two fields named 'latitude' and 'longitude'. +# Those should be in the edit form. This widget should NOT be in the +# edit form (or it will submit a bunch of spurious fields, plus pressing +# "enter" in the search box will submit the form). + + + + + +

+ + + + + +
+
+
+ + diff --git a/httemplate/elements/tower_sector.html b/httemplate/elements/tower_sector.html deleted file mode 100644 index dacb5ba92..000000000 --- a/httemplate/elements/tower_sector.html +++ /dev/null @@ -1,69 +0,0 @@ -% unless ( $opt{'js_only'} ) { - - - - - -% foreach my $field ( @fields ) { - - -% } - -
- get($field) |h %>" - <% $onchange %> - >
- <% $label{$field} %> -
- - -% } -<%init> - -my( %opt ) = @_; - -my $name = $opt{'element_name'} || $opt{'field'} || 'sectornum'; -my $id = $opt{'id'} || 'sectornum'; - -my $curr_value = $opt{'curr_value'} || $opt{'value'}; - -my $onchange = ''; -if ( $opt{'onchange'} ) { - $onchange = $opt{'onchange'}; - $onchange .= '(this)' unless $onchange =~ /\(\w*\);?$/; - $onchange =~ s/\(what\);/\(this\);/g; #ugh, terrible hack. all onchange - #callbacks should act the same - $onchange = 'onChange="'. $onchange. '"'; -} - -my $tower_sector; -if ( $curr_value ) { - $tower_sector = qsearchs('tower_sector', { 'sectornum' => $curr_value } ); -} else { - $tower_sector = new FS::tower_sector {}; -} - -my %size = ( 'title' => 12 ); - -tie my %label, 'Tie::IxHash', - 'sectorname' => 'Name', - 'ip_addr' => 'IP Address', - 'height' => 'Height', - 'freq_mhz' => 'Freq. (MHz)', - 'direction' => 'Direction', # or a button to set these to 0 for omni - 'downtilt' => 'Downtilt', - 'width' => 'Horiz. width', - 'v_width' => 'Vert. width', - 'sector_range' => 'Range', - 'db_high' => 'High quality margin (dB)', - 'db_low' => 'Low quality margin (dB)', -; - -my @fields = keys %label; - - diff --git a/httemplate/elements/tr-tower_sectors.html b/httemplate/elements/tr-tower_sectors.html index 5351becd8..4e8f3fb47 100644 --- a/httemplate/elements/tr-tower_sectors.html +++ b/httemplate/elements/tr-tower_sectors.html @@ -31,7 +31,7 @@ if ( $cgi->param('error') ) { my $id = $opt{id} || $opt{field} || 'sectornum'; -<& tablebreak-tr-title.html, %opt &> +<& tablebreak-tr-title.html, value => 'Sectors' &>
@@ -172,8 +173,8 @@ var initMap = function() { var canvas = $('#map_canvas'); // set window height correctly - canvas.css('height', window.innerHeight - (canvas.offset().top) - 1); - canvas.css('width', window.innerWidth - (canvas.offset().left) * 2); + canvas.css('height', window.innerHeight - (canvas.offset().top) - 30); + canvas.css('width', window.innerWidth - 30); map = new google.maps.Map(canvas[0], { zoom: 6 }); @@ -194,7 +195,7 @@ var initMap = function() { map.fitBounds(places[0].geometry.viewport); } else { map.setCenter(places[0].geometry.location); - map.setZoom(13); + map.setZoom(14); } } }); @@ -225,7 +226,6 @@ my @towers = qsearch('tower', { 'longitude' => { op=>'!=', value=>''}, }); my %sectors; # towernum => arrayref -my @overlays; my @towernums; foreach my $tower (@towers) { @@ -257,17 +257,6 @@ foreach my $tower (@towers) { }; $sectors{$towernum} = [ $tower->tower_sector ]; - foreach my $sector (@{ $sectors{$towernum} }) { - if ( length($sector->image) > 0 ) { - my $o = { - url => $fsurl.'view/sector_map-png.cgi?' . $sector->sectornum - }; - foreach (qw(south north west east)) { - $o->{$_} = $sector->get($_) + 0; - } - push @overlays, $o; - }; - }; } # foreach $tower