StatusBar.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. import DomUtil from './common/doms.js'
  2. import '../Assets/styles/StatusBar.css';
  3. /**
  4. * 状态栏
  5. */
  6. class StatusBar {
  7. /**
  8. * 状态栏工具类
  9. * @param {Viewer} viewer - 三维场景
  10. */
  11. constructor(viewer) {
  12. if (!viewer) throw new Error('viewer is required!');
  13. this._viewer = viewer;
  14. this._show = false; //初始化显示状态
  15. this._handler;
  16. this._posX;
  17. this._posY;
  18. this._posZ;
  19. this._cameraHeight;
  20. this._pitch;
  21. this._heading;
  22. this._scale;
  23. this.initListener()
  24. }
  25. /**
  26. * 状态栏参数
  27. * @readonly
  28. */
  29. get params() {
  30. return {
  31. posX: this._posX, //经度
  32. posY: this._posY, //维度
  33. posZ: this._posZ, //模型高度
  34. cameraHeight: this._cameraHeight, //相机视角高度
  35. pitch: this._pitch, //俯仰角
  36. heading: this._heading, //方向
  37. scale: this._scale //比例尺
  38. }
  39. }
  40. get statusDom() {
  41. let innerHtml = `
  42. <span class="status-scale">
  43. 比例尺:
  44. <span class="scale-border">
  45. ${this._scale}
  46. </span>
  47. </span>
  48. <span class="status-position">
  49. <span id="status_spaceInfo">空间信息</span>
  50. 刷帧率:<span id="status_ms"></span>|<span id="status_fps"></span>
  51. </span>
  52. `
  53. return innerHtml
  54. }
  55. /**
  56. * 控制显示Boolean常量
  57. * @constant
  58. */
  59. get show() {
  60. return this._show
  61. }
  62. set show(bool) {
  63. bool ? this.createStatusBar() : this.removeStatusBar()
  64. this._show = bool
  65. }
  66. initListener() {
  67. const $this = this
  68. const scene = this._viewer.scene
  69. this._scaleListener = function() {
  70. let width = scene.canvas.clientWidth
  71. let height = scene.canvas.clientHeight
  72. let left = scene.camera.getPickRay(
  73. new Cesium.Cartesian2((width / 2) | 0, height - 1)
  74. )
  75. let right = scene.camera.getPickRay(
  76. new Cesium.Cartesian2((1 + width / 2) | 0, height - 1)
  77. )
  78. let globe = scene.globe
  79. let leftPosition = globe.pick(left, scene)
  80. let rightPosition = globe.pick(right, scene)
  81. if (leftPosition && rightPosition) {
  82. let geodesic = new Cesium.EllipsoidGeodesic()
  83. let leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition)
  84. let rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition)
  85. geodesic.setEndPoints(leftCartographic, rightCartographic)
  86. let distance = geodesic.surfaceDistance
  87. let curScaleNum = $this.closest(distance / 10)
  88. if (curScaleNum < 1) {
  89. $this._scale = curScaleNum * 1000 + 'm'
  90. } else {
  91. $this._scale = curScaleNum + 'km'
  92. }
  93. }
  94. document.getElementsByClassName("scale-border")[0].innerText = $this._scale;
  95. if (document.getElementsByClassName("cesium-performanceDisplay-ms").length > 0) {
  96. document.getElementById("status_ms").innerText = document.getElementsByClassName("cesium-performanceDisplay-ms")[0].innerText;
  97. }
  98. if (document.getElementsByClassName("cesium-performanceDisplay-fps").length > 0) {
  99. document.getElementById("status_fps").innerText = document.getElementsByClassName("cesium-performanceDisplay-fps")[0].innerText;
  100. }
  101. }
  102. }
  103. createStatusBar() {
  104. const _delegate = this._viewer
  105. this.initHandler(_delegate)
  106. this.initScale(_delegate, true)
  107. this._domContainer = DomUtil.create(
  108. 'div',
  109. 'lk-status-bar',
  110. document.getElementById(this._viewer._container.id)
  111. )
  112. this._domContainer.innerHTML = this.statusDom;
  113. // var canvas = this._viewer.canvas; // 获取画布
  114. // this._domContainer.style.width = canvas.width + "px";
  115. // console.log('画布', canvas.width)
  116. }
  117. removeStatusBar() {
  118. this.initScale(this._viewer, false)
  119. if (this._handler) {
  120. this._handler.destroy()
  121. }
  122. if (this._domContainer) {
  123. DomUtil.remove(this._domContainer)
  124. }
  125. }
  126. initHandler(viewer) {
  127. const $this = this
  128. this._handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas)
  129. const mouseOverHandler = function(movement) {
  130. /* 识别屏幕位置 */
  131. let loc = $this._getScreenClickPositionAndHeight(movement.endPosition);
  132. if (!Cesium.defined(loc)) return;
  133. if (!loc.lng) return;
  134. $this._posX = loc.lng.toFixed(8);
  135. $this._posY = loc.lat.toFixed(8);
  136. $this._posZ = loc.height.toFixed(2);
  137. // const cameraH = viewer.camera.positionCartographic.height
  138. // $this._cameraHeight =
  139. // cameraH < 1000 ?
  140. // cameraH.toFixed(2) + 'm' :
  141. // (cameraH / 1000).toFixed(2) + 'km';
  142. // $this._pitch = Number(viewer.scene.camera.pitch).toFixed(2);
  143. // $this._heading = Number(viewer.scene.camera.heading).toFixed(2);
  144. document.getElementById("status_spaceInfo").innerHTML = `
  145. <span>经度:${$this._posX}</span>
  146. <span>纬度:${$this._posY}</span>
  147. <span>高度:${$this._posZ}</span>
  148. `;
  149. }
  150. this._handler.setInputAction(
  151. mouseOverHandler,
  152. Cesium.ScreenSpaceEventType.MOUSE_MOVE
  153. )
  154. }
  155. initScale(viewer, bool) {
  156. const scene = viewer.scene
  157. bool
  158. ?
  159. scene.postRender.addEventListener(this._scaleListener) :
  160. scene.postRender.removeEventListener(this._scaleListener)
  161. }
  162. closest(num) {
  163. const scaleList = [
  164. 0.001,
  165. 0.002,
  166. 0.003,
  167. 0.005,
  168. 0.01,
  169. 0.015,
  170. 0.02,
  171. 0.025,
  172. 0.03,
  173. 0.035,
  174. 0.04,
  175. 0.045,
  176. 0.05,
  177. 0.06,
  178. 0.07,
  179. 0.08,
  180. 0.09,
  181. 0.1,
  182. 0.12,
  183. 0.15,
  184. 0.2,
  185. 0.25,
  186. 0.3,
  187. 0.5,
  188. 1,
  189. 2,
  190. 3,
  191. 5,
  192. 10,
  193. 15,
  194. 20,
  195. 25,
  196. 30,
  197. 35,
  198. 40,
  199. 45,
  200. 50,
  201. 60,
  202. 70,
  203. 80,
  204. 90,
  205. 100,
  206. 120,
  207. 150,
  208. 200,
  209. 250,
  210. 300,
  211. 500,
  212. 1000,
  213. 2000,
  214. 5000,
  215. 10000,
  216. 100000,
  217. 500000,
  218. 1000000
  219. ]
  220. let ret = scaleList[0]
  221. let distance = Math.abs(ret - num)
  222. for (let i = 1; i < scaleList.length; i++) {
  223. let newDistance = Math.abs(scaleList[i] - num)
  224. if (newDistance < distance) {
  225. distance = newDistance
  226. ret = scaleList[i]
  227. }
  228. }
  229. return ret
  230. }
  231. /**
  232. * 根据地形或实景或模型检测当前屏幕位置的经纬度及高度
  233. * @ignore 生成方法时不对外公开
  234. * @param {JSON} screenPoint 屏幕坐标
  235. * @param {Number} screenPoint.x 屏幕坐标x
  236. * @param {Number} screenPoint.y 屏幕坐标y
  237. * @return {JSON} 位置信息{lng,lat,height}
  238. */
  239. _getScreenClickPositionAndHeight(screenPoint) {
  240. var lng = undefined,
  241. lat = undefined,
  242. height = undefined;
  243. /* 从相机位置到 windowPosition 处的像素创建射线在世界坐标系中 */
  244. var ray = this._viewer.scene.camera.getPickRay(screenPoint);
  245. /* 找到射线与渲染的地球表面之间的交点 */
  246. var position = this._viewer.scene.globe.pick(ray, this._viewer.scene);
  247. if (position) {
  248. /* 获取地理位置的制图表达 */
  249. var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(position);
  250. cartographic = Cesium.Cartographic.fromCartesian(position);
  251. /* 查询屏幕位置的要素 */
  252. var feature = this._viewer.scene.pick(screenPoint);
  253. if (feature === undefined && Cesium.defined(cartographic)) {
  254. lng = this._arcToDegree(cartographic.longitude);
  255. lat = this._arcToDegree(cartographic.latitude);
  256. height = cartographic.height;
  257. } else {
  258. var cartesian = this._viewer.scene.pickPosition(screenPoint);
  259. if (Cesium.defined(cartesian)) {
  260. var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
  261. if (Cesium.defined(cartographic)) {
  262. lng = this._arcToDegree(cartographic.longitude);
  263. lat = this._arcToDegree(cartographic.latitude);
  264. height = cartographic.height;
  265. }
  266. }
  267. }
  268. }
  269. /* 返回结果 */
  270. return {
  271. lng: lng,
  272. lat: lat,
  273. height: height,
  274. }
  275. }
  276. /**
  277. * 弧度转度
  278. * @ignore 生成方法时不对外公开
  279. * @param {Number} arc 弧度
  280. * @return {Number} 角度
  281. */
  282. _arcToDegree(arc) {
  283. return arc / Math.PI * 180;
  284. }
  285. }
  286. export default StatusBar