You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

248 lines
7.7 KiB

  1. const turf = {
  2. area: require('@turf/area').default,
  3. length: require('@turf/length').default
  4. }
  5. const tabs = require('modulekit-tabs')
  6. const formatUnits = require('./formatUnits')
  7. const displayBlock = require('./displayBlock')
  8. require('./GeoInfo.css')
  9. function heading (value) {
  10. return [ 'N', 'NE', 'E', 'SE', 'S', 'SW', 'W', 'NW', 'N' ][Math.round(value / 45)]
  11. }
  12. register_hook('init', function () {
  13. let tab = new tabs.Tab({
  14. id: 'search',
  15. weight: -1
  16. })
  17. tab.content.classList.add('geo-info')
  18. global.tabs.add(tab)
  19. updateTabHeader(tab.header)
  20. tab.header.title = lang('geoinfo:header')
  21. let crosshairIcon = L.icon({
  22. iconUrl: 'img/crosshair.png',
  23. iconSize: [21, 21],
  24. iconAnchor: [10, 10],
  25. })
  26. let crosshair = new L.marker([0,0], {
  27. icon: crosshairIcon,
  28. clickable:false,
  29. pane: "crosshair800"
  30. })
  31. global.map.createPane('crosshair800')
  32. global.map.getPane('crosshair800').style.zIndex = 800
  33. global.map.getPane('crosshair800').style.pointerEvents = 'none'
  34. let domZoom = document.createElement('div')
  35. domZoom.className = 'zoom'
  36. domZoom.title = lang('geoinfo:zoom')
  37. tab.content.appendChild(domZoom)
  38. let domBBoxNW = document.createElement('div')
  39. domBBoxNW.className = 'bbox-nw-corner'
  40. domBBoxNW.title = lang('geoinfo:nw-corner')
  41. tab.content.appendChild(domBBoxNW)
  42. let domCenter = document.createElement('div')
  43. domCenter.className = 'bbox-center'
  44. domCenter.title = lang('geoinfo:center')
  45. tab.content.appendChild(domCenter)
  46. let domBBoxSE = document.createElement('div')
  47. domBBoxSE.className = 'bbox-se-corner'
  48. domBBoxSE.title = lang('geoinfo:se-corner')
  49. tab.content.appendChild(domBBoxSE)
  50. let domMouse = document.createElement('div')
  51. domMouse.className = 'mouse empty'
  52. domMouse.title = lang('geoinfo:mouse')
  53. tab.content.appendChild(domMouse)
  54. let domLocation = document.createElement('div')
  55. domLocation.title = lang('geoinfo:location')
  56. domLocation.className = 'location empty'
  57. tab.content.appendChild(domLocation)
  58. function getPrecision () {
  59. let zoom = global.map.getZoom()
  60. return zoom > 16 ? 5
  61. : zoom > 8 ? 4
  62. : zoom > 4 ? 3
  63. : zoom > 2 ? 2
  64. : zoom > 1 ? 1
  65. : 0
  66. }
  67. function updateMapView () {
  68. crosshair.setLatLng(global.map.getCenter())
  69. let scale = formatUnits.distance(global.map.getMetersPerPixel())
  70. let scale2 = formatUnits.area(Math.pow(global.map.getMetersPerPixel(), 2))
  71. let precision = getPrecision()
  72. domZoom.innerHTML = '<span class="value">z' +
  73. Math.round(global.map.getZoom()) + ', ' +
  74. scale + '/px, ' +
  75. scale2 + '/px²' +
  76. '</span>'
  77. let bounds = map.getBounds()
  78. domBBoxNW.innerHTML = '<span class="value">' + formatUnits.coord(bounds.getNorthWest().wrap(), { precision }) + '</span>'
  79. domCenter.innerHTML = '<span class="value">' + formatUnits.coord(bounds.getCenter().wrap(), { precision }) + '</span>'
  80. domBBoxSE.innerHTML = '<span class="value">' + formatUnits.coord(bounds.getSouthEast().wrap(), { precision }) + '</span>'
  81. }
  82. let lastMouseEvent
  83. function updateMouse (e) {
  84. if (!e) {
  85. e = lastMouseEvent
  86. }
  87. if (e) {
  88. let precision = getPrecision()
  89. domMouse.innerHTML = '<span class="value">' + formatUnits.coord(e.latlng.wrap(), { precision }) + '</span>'
  90. domMouse.classList.remove('empty')
  91. } else {
  92. removeMouse()
  93. }
  94. lastMouseEvent = e
  95. }
  96. function removeMouse () {
  97. lastMouseEvent = null
  98. domMouse.innerHTML = ''
  99. domMouse.classList.add('empty')
  100. }
  101. let lastLocation
  102. function updateLocation (e) {
  103. if (e) {
  104. lastLocation = e
  105. } else {
  106. e = lastLocation
  107. }
  108. if (e) {
  109. domLocation.innerHTML = '<span class="value">' + formatUnits.coord(e.latlng.wrap(), { precision: 5 }) +
  110. (typeof e.accuracy !== 'undefined' ? (global.options.formatUnitsCoordSpacer || ', ') + '± ' + formatUnits.distance(e.accuracy.toFixed(0)) : '') + '<br/>' +
  111. (typeof e.altitude !== 'undefined' ? '<i class="fas fa-mountain"></i> ' + formatUnits.height(e.altitude) + (typeof e.altitudeAccuracy !== 'undefined' ? ' ± ' + formatUnits.distance(e.altitudeAccuracy) : '') + ' ' : '') +
  112. (typeof e.speed !== 'undefined' ? '<i class="fas fa-tachometer-alt"></i> ' + formatUnits.speed(e.speed) + ' ' : '') +
  113. (typeof e.heading !== 'undefined' ? '<i class="fas fa-compass"></i> ' + lang('heading:' + heading(e.heading)) + ' (' + e.heading.toFixed(0) + '°)' : '') +
  114. '</span>'
  115. domLocation.classList.remove('empty')
  116. }
  117. }
  118. function saveLocation (e) {
  119. lastLocation = e
  120. }
  121. global.map.on('move', () => {
  122. updateTabHeader(tab.header)
  123. })
  124. global.map.on('locationfound', saveLocation)
  125. tab.on('select', () => {
  126. crosshair.addTo(global.map)
  127. updateMapView()
  128. updateLocation()
  129. global.map.on('move', updateMapView)
  130. global.map.on('mousemove', updateMouse)
  131. global.map.on('mouseout', removeMouse)
  132. global.map.off('locationfound', saveLocation)
  133. global.map.on('locationfound', updateLocation)
  134. })
  135. tab.on('unselect', () => {
  136. crosshair.removeFrom(global.map)
  137. global.map.off('move', updateMapView)
  138. global.map.off('mousemove', updateMouse)
  139. global.map.off('mouseout', removeMouse)
  140. global.map.off('locationfound', updateLocation)
  141. global.map.on('locationfound', saveLocation)
  142. })
  143. register_hook('format-units-refresh', updateMapView)
  144. register_hook('format-units-refresh', updateMouse)
  145. register_hook('format-units-refresh', removeMouse)
  146. register_hook('format-units-refresh', updateLocation)
  147. })
  148. let showDetailsCurrent
  149. register_hook('show-details', (data, category, dom, callback) => {
  150. let div = document.createElement('div')
  151. div.className = 'geo-info'
  152. displayBlock({
  153. dom,
  154. title: lang('geoinfo:header'),
  155. content: div,
  156. order: 5,
  157. })
  158. showDetailsCurrent = [ data, category, div ]
  159. geoInfoShowDetails.apply(this, showDetailsCurrent)
  160. callback()
  161. })
  162. register_hook('format-units-refresh', () => {
  163. if (showDetailsCurrent) {
  164. showDetailsCurrent[2].innerHTML = ''
  165. geoInfoShowDetails.apply(this, showDetailsCurrent)
  166. }
  167. })
  168. function geoInfoShowDetails (data, category, div) {
  169. let ob = data.object
  170. let result = ''
  171. let geojson = ob.GeoJSON()
  172. let area = turf.area(geojson)
  173. let length = turf.length(geojson) * 1000
  174. if (area !== 0 || length !== 0) {
  175. result += '<div class="object-shape">' +
  176. '<span class="value">' +
  177. lang('geoinfo:length') + ': ' + formatUnits.distance(length) +
  178. (area === 0 ? '' : ', ' + lang('geoinfo:area') + ': ' + formatUnits.area(area)) +
  179. '</span></div>'
  180. }
  181. if (ob.bounds.minlat !== ob.bounds.maxlat || ob.bounds.minlon !== ob.bounds.maxlon) {
  182. result += '<div class="object-nw-corner" title="' + lang('geoinfo:nw-corner') + '"><span class="value">' + formatUnits.coord({ lat: ob.bounds.minlat, lng: ob.bounds.maxlon }) + '</span></div>'
  183. }
  184. result += '<div class="object-center" title="' + lang('geoinfo:centroid') + '"><span class="value">' + formatUnits.coord({ lat: ob.center.lat, lng: ob.center.lon }) + '</span></div>'
  185. if (ob.bounds.minlat !== ob.bounds.maxlat || ob.bounds.minlon !== ob.bounds.maxlon) {
  186. result += '<div class="object-se-corner" title="' + lang('geoinfo:se-corner') + '"><span class="value">' + formatUnits.coord({ lat: ob.bounds.maxlat, lng: ob.bounds.minlon }) + '</span></div>'
  187. }
  188. div.innerHTML = result
  189. }
  190. function updateTabHeader (header) {
  191. if (!global.map._loaded) {
  192. return
  193. }
  194. let center = global.map.getCenter().wrap()
  195. if (center.lng < -35) {
  196. header.innerHTML = '<i class="fas fa-globe-americas"></i>'
  197. } else if (center.lng > 80) {
  198. header.innerHTML = '<i class="fas fa-globe-asia"></i>'
  199. } else if (center.lat < 30) {
  200. header.innerHTML = '<i class="fas fa-globe-africa"></i>'
  201. } else {
  202. header.innerHTML = '<i class="fas fa-globe-europe"></i>'
  203. }
  204. }