[Gridsquare Map] Added display of coordinates, gridsquare, distance and bearing when mouseover
这个提交包含在:
		
							父节点
							
								
									a6da3c1277
								
							
						
					
					
						当前提交
						36fdce5eca
					
				
					共有  4 个文件被更改,包括 148 次插入 和 2 次删除
				
			
		|  | @ -11,6 +11,9 @@ class Gridmap extends CI_Controller { | ||||||
| 
 | 
 | ||||||
|         $this->load->model('bands'); |         $this->load->model('bands'); | ||||||
|         $this->load->model('gridmap_model'); |         $this->load->model('gridmap_model'); | ||||||
|  | 		$this->load->model('stations'); | ||||||
|  | 
 | ||||||
|  | 		$data['homegrid'] = explode(',', $this->stations->find_gridsquare()); | ||||||
| 
 | 
 | ||||||
|         $data['modes'] = $this->gridmap_model->get_worked_modes(); |         $data['modes'] = $this->gridmap_model->get_worked_modes(); | ||||||
| 		$data['bands'] = $this->bands->get_worked_bands(); | 		$data['bands'] = $this->bands->get_worked_bands(); | ||||||
|  | @ -27,6 +30,7 @@ class Gridmap extends CI_Controller { | ||||||
| 
 | 
 | ||||||
|         $footerData = []; |         $footerData = []; | ||||||
| 		$footerData['scripts'] = [ | 		$footerData['scripts'] = [ | ||||||
|  | 			'assets/js/leaflet/geocoding.js', | ||||||
| 			'assets/js/leaflet/L.MaidenheadColouredGridMap.js', | 			'assets/js/leaflet/L.MaidenheadColouredGridMap.js', | ||||||
| 			'assets/js/sections/gridmap.js?' | 			'assets/js/sections/gridmap.js?' | ||||||
| 		]; | 		]; | ||||||
|  |  | ||||||
|  | @ -6,9 +6,9 @@ | ||||||
|   padding: 6px 8px; |   padding: 6px 8px; | ||||||
|   font: 14px Arial, Helvetica, sans-serif; |   font: 14px Arial, Helvetica, sans-serif; | ||||||
|   background: white; |   background: white; | ||||||
|   background: rgba(255, 255, 255, 0.8); |  | ||||||
|   line-height: 24px; |   line-height: 24px; | ||||||
|   color: #555;
 |   color: #555;
 | ||||||
|  |   border-radius: 10px; | ||||||
| } | } | ||||||
| .legend h4 { | .legend h4 { | ||||||
|   text-align: center; |   text-align: center; | ||||||
|  | @ -25,7 +25,13 @@ | ||||||
|   height: 18px; |   height: 18px; | ||||||
|   float: left; |   float: left; | ||||||
|   margin: 0 8px 0 0; |   margin: 0 8px 0 0; | ||||||
|   opacity: 0.7; | } | ||||||
|  | .coordinates { | ||||||
|  |     justify-content: center;  | ||||||
|  |     align-items: stretch; | ||||||
|  | } | ||||||
|  | .cohidden { | ||||||
|  |     display:none; | ||||||
| } | } | ||||||
| </style> | </style> | ||||||
| <div class="container"> | <div class="container"> | ||||||
|  | @ -94,10 +100,23 @@ | ||||||
| <div id="gridmapcontainer"> | <div id="gridmapcontainer"> | ||||||
| 	<div id="gridsquare_map" style="width: 100%; height: 800px"></div> | 	<div id="gridsquare_map" style="width: 100%; height: 800px"></div> | ||||||
| </div> | </div> | ||||||
|  | <div class="coordinates text-center d-flex"> | ||||||
|  |         <div class="cohidden">Latitude: </div> | ||||||
|  |         <div class="cohidden col-auto text-success font-weight-bold" id="latDeg"></div> | ||||||
|  |         <div class="cohidden">Longitude: </div> | ||||||
|  |         <div class="cohidden col-auto text-success font-weight-bold" id="lngDeg"></div> | ||||||
|  |         <div class="cohidden">Gridsquare: </div> | ||||||
|  |         <div class="cohidden col-auto text-success font-weight-bold" id="locator"></div> | ||||||
|  |         <div class="cohidden">Distance: </div> | ||||||
|  |         <div class="cohidden col-auto text-success font-weight-bold" id="distance"></div> | ||||||
|  |         <div class="cohidden">Bearing: </div> | ||||||
|  |         <div class="cohidden col-auto text-success font-weight-bold" id="bearing"></div> | ||||||
|  | </div> | ||||||
| <script>var gridsquaremap = true; | <script>var gridsquaremap = true; | ||||||
| <?php | <?php | ||||||
|     echo 'var jslayer ="' . $layer .'";'; |     echo 'var jslayer ="' . $layer .'";'; | ||||||
|     echo "var jsattribution ='" . $attribution . "';"; |     echo "var jsattribution ='" . $attribution . "';"; | ||||||
|  |     echo "var homegrid ='" . strtoupper($homegrid[0]) . "';"; | ||||||
| 
 | 
 | ||||||
|     echo 'var gridsquares_gridsquares = "' . $gridsquares_gridsquares . '";'; |     echo 'var gridsquares_gridsquares = "' . $gridsquares_gridsquares . '";'; | ||||||
|     echo 'var gridsquares_gridsquares_confirmed = "' . $gridsquares_gridsquares_confirmed . '";'; |     echo 'var gridsquares_gridsquares_confirmed = "' . $gridsquares_gridsquares_confirmed . '";'; | ||||||
|  |  | ||||||
							
								
								
									
										121
									
								
								assets/js/leaflet/geocoding.js
									
									
									
									
									
										普通文件
									
								
							
							
						
						
									
										121
									
								
								assets/js/leaflet/geocoding.js
									
									
									
									
									
										普通文件
									
								
							|  | @ -0,0 +1,121 @@ | ||||||
|  | const isValidLocatorString = locatorString => locatorString.match(/^[A-Ra-r][A-Ra-r]\d\d[A-Xa-x][A-Xa-x]/) !== null; | ||||||
|  | const charToNumber = char => char.toUpperCase().charCodeAt(0) - CHAR_CODE_OFFSET; | ||||||
|  | const numberToChar = number => String.fromCharCode(number + CHAR_CODE_OFFSET); | ||||||
|  | const CHAR_CODE_OFFSET = 65; | ||||||
|  | const degToRad = deg => (deg % 360) * Math.PI / 180; | ||||||
|  | const radToDeg = rad => (rad / Math.PI *180) % 360; | ||||||
|  | const isValidPoint = (lat, lng) => (lat >= -90 && lat <= 90) && (lng >= -180 && lng <= 180); | ||||||
|  | 
 | ||||||
|  | function ConvertDDToDMS(lat, lng) { | ||||||
|  | 	var LatLng = []; | ||||||
|  | 
 | ||||||
|  | 	if (lng < -180) { | ||||||
|  | 		lng = lng + 360; | ||||||
|  | 	} | ||||||
|  | 	if (lng > 180)  { | ||||||
|  | 		lng = lng - 360; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	LatLng['latDeg'] = (lat < 0 ? "S" : "N") + " " + (0 | (lat < 0 ? (lat = -lat) : lat)) + "° " + (0 | (((lat += 1e-9) % 1) * 60)) + "' " + ((0 | (((lat * 60) % 1) * 6000)) / 100) + "\""; | ||||||
|  | 
 | ||||||
|  | 	LatLng['lngDeg'] = (lng < 0 ? "W" : "E") + " " + (0 | (lng < 0 ? (lng = -lng) : lng)) + "° " + (0 | (((lng += 1e-9) % 1) * 60)) + "' " + ((0 | (((lng * 60) % 1) * 6000)) / 100) + "\""; | ||||||
|  | 
 | ||||||
|  | 	return LatLng; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const latLngToLocator = (lat, lng) => { | ||||||
|  | 	if (lng < -180) { | ||||||
|  | 		lng = lng + 360; | ||||||
|  | 	} | ||||||
|  | 	if (lng > 180)  { | ||||||
|  | 		lng = lng - 360; | ||||||
|  | 	} | ||||||
|  | 	if (!isValidPoint(lat, lng)) { | ||||||
|  | 		throw new Error('Input is not a valid coordinate'); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	const longitude = lng + 180; | ||||||
|  | 	const latitude = lat + 90; | ||||||
|  | 
 | ||||||
|  | 	const fieldLng = numberToChar(Math.floor(longitude / 20)); | ||||||
|  | 	const fieldLat = numberToChar(Math.floor(latitude / 10)); | ||||||
|  | 
 | ||||||
|  | 	const squareLng = Math.floor(longitude % 20 / 2); | ||||||
|  | 	const squareLat = Math.floor(latitude % 10); | ||||||
|  | 
 | ||||||
|  | 	const subsquareLng = numberToChar(Math.floor((longitude % 20 % 2) * 12)).toLowerCase(); | ||||||
|  | 	const subsquareLat = numberToChar((latitude % 10 - squareLat) * 24).toLowerCase(); | ||||||
|  | 
 | ||||||
|  | 	return fieldLng + fieldLat + squareLng + squareLat + subsquareLng + subsquareLat; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function onMapMove(event) { | ||||||
|  | 	var LatLng = event.latlng; | ||||||
|  | 	var lat = LatLng.lat;  | ||||||
|  | 	var lng = LatLng.lng; 					 | ||||||
|  | 	var LatLng2 = ConvertDDToDMS(lat, lng); | ||||||
|  | 	$('#latDeg').html(LatLng2.latDeg); | ||||||
|  | 	$('#lngDeg').html(LatLng2.lngDeg); | ||||||
|  | 	var locator = latLngToLocator(lat,lng); | ||||||
|  | 	$('#locator').html(locator); | ||||||
|  | 	var distance = bearingDistance(homegrid, locator); | ||||||
|  | 
 | ||||||
|  | 	$('#bearing').html(distance.deg + ' deg'); | ||||||
|  | 	$('#distance').html(Math.round(distance.km * 10) / 10 + ' km'); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const bearingDistance = (from, to) => { | ||||||
|  | 	const fromCoords = locatorToLatLng(from); | ||||||
|  | 	const toCoords = locatorToLatLng(to); | ||||||
|  | 	const dLat = degToRad(toCoords[0] - fromCoords[0]); | ||||||
|  | 	const dLon = degToRad(toCoords[1] - fromCoords[1]); | ||||||
|  | 	const fromLat = degToRad(fromCoords[0]); | ||||||
|  | 	const toLat = degToRad(toCoords[0]); | ||||||
|  | 	const a = Math.pow(Math.sin(dLat / 2), 2) + Math.pow(Math.sin(dLon / 2), 2) * Math.cos(fromLat) * Math.cos(toLat); | ||||||
|  | 	const b = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); | ||||||
|  | 	 | ||||||
|  | 	const y = (dLon) * Math.cos(fromLat) * Math.cos(toLat); | ||||||
|  | 	const x = Math.sin(toLat) - Math.sin(fromLat) * Math.cos(b); | ||||||
|  | 	 | ||||||
|  | 	let az = Math.atan2(y, x); | ||||||
|  | 	 | ||||||
|  | 	if (az < 0) { | ||||||
|  | 		az += 2 * Math.PI; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	return { | ||||||
|  | 		km: b * 6371, | ||||||
|  | 		deg: calcAngle(fromCoords, toCoords) | ||||||
|  | 	}; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | var calcAngle = function (p1, p2) { | ||||||
|  | 	var lat1 = p1[0] / 180 * Math.PI; | ||||||
|  | 	var lat2 = p2[0] / 180 * Math.PI; | ||||||
|  | 	var lng1 = p1[1] / 180 * Math.PI; | ||||||
|  | 	var lng2 = p2[1] / 180 * Math.PI; | ||||||
|  | 	var y = Math.sin(lng2-lng1) * Math.cos(lat2); | ||||||
|  | 	var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(lng2-lng1); | ||||||
|  | 	var brng = (Math.atan2(y, x) * 180 / Math.PI + 360).toFixed(0); | ||||||
|  | 
 | ||||||
|  | 	return (brng % 360); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const locatorToLatLng = (locatorString) => { | ||||||
|  | 	locatorString += 'll'; // append subsquare in case is 4 chars long...  If not, is ignored.
 | ||||||
|  | 	if (!isValidLocatorString(locatorString)) { | ||||||
|  | 		throw new Error('Input is not valid locator string'); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	const fieldLng = charToNumber(locatorString[0]) * 20; | ||||||
|  | 	const fieldLat = charToNumber(locatorString[1]) * 10; | ||||||
|  | 	const squareLng = Number.parseInt(locatorString[2]) * 2; | ||||||
|  | 	const squareLat = Number.parseInt(locatorString[3]); | ||||||
|  | 	const subsquareLng = (charToNumber(locatorString[4]) + 0.5) / 12; | ||||||
|  | 	const subsquareLat = (charToNumber(locatorString[5]) + 0.5) / 24; | ||||||
|  | 	 | ||||||
|  | 	return [ | ||||||
|  | 		fieldLat + squareLat + subsquareLat - 90, | ||||||
|  | 		fieldLng + squareLng + subsquareLng - 180 | ||||||
|  | 	]; | ||||||
|  | }; | ||||||
|  | @ -40,6 +40,7 @@ function gridPlot(form) { | ||||||
|             sat: $("#sats").val(), |             sat: $("#sats").val(), | ||||||
| 		}, | 		}, | ||||||
| 		success: function (data) { | 		success: function (data) { | ||||||
|  |             $('.cohidden').show(); | ||||||
|             $(".ld-ext-right").removeClass('running'); |             $(".ld-ext-right").removeClass('running'); | ||||||
|             $(".ld-ext-right").prop('disabled', false); |             $(".ld-ext-right").prop('disabled', false); | ||||||
|             $('#plot').prop("disabled", false); |             $('#plot').prop("disabled", false); | ||||||
|  | @ -89,6 +90,7 @@ function gridPlot(form) { | ||||||
|             legend.addTo(map); |             legend.addTo(map); | ||||||
| 
 | 
 | ||||||
|             var maidenhead = L.maidenhead().addTo(map); |             var maidenhead = L.maidenhead().addTo(map); | ||||||
|  |             map.on('mousemove', onMapMove); | ||||||
| 		}, | 		}, | ||||||
| 		error: function (data) { | 		error: function (data) { | ||||||
| 		}, | 		}, | ||||||
|  |  | ||||||
		正在加载…
	
		在新工单中引用