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.

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