Cesium实现带帧率显示的状态栏,cesium显示帧率
实现效果

源码
1、PerformaceDisplay.js
/**
* 显示帧率的插件
*/
export default class PerformanceDisplay {
constructor() {
this._lastFpsSampleTime = Cesium.getTimestamp()
this._fpsFrameCount = 0
this._fpsText = document.createTextNode('')
}
update(container) {
const time = Cesium.getTimestamp()
this._fpsFrameCount++
const fpsElapsedTime = time - this._lastFpsSampleTime
if (fpsElapsedTime > 1000) {
let fps = ((this._fpsFrameCount * 1000) / fpsElapsedTime) | 0
this._fpsText.nodeValue = `● ${fps} FPS`
this._lastFpsSampleTime = time
this._fpsFrameCount = 0
if (fps < 60) {
container.style.color = '#ff0'
} else if (fps < 30) {
container.style.color = '#f00'
} else {
container.style.color = '#0f0'
}
container.appendChild(this._fpsText)
}
}
destroy() {
return Cesium.destroyObject(this)
}
}
2、StatusBar.js
import PerformanceDisplay from "./PerformaceDisplay";
export default class StatusBar {
constructor(viewer, el) {
this.el = el // 挂载的节点
this.viewer = viewer
this.divDom = undefined
this.longitude = '--'
this.latitude = '--'
this.pitch = '--'
this.heading = '--'
this._handler = undefined
this._cameraHeight = '--'
this.scale = '--'
this.performanceDisplay = undefined
this.width = this.viewer.scene.canvas.clientWidth
this.height = this.viewer.scene.canvas.clientHeight
this.scaleList = [
1, 2, 3, 5, 10, 20, 30, 50, 100, 200, 300, 500, 1000, 2000, 3000, 5000, 10000, 20000,
30000, 50000, 100000, 200000, 300000, 500000, 1000000, 2000000, 3000000, 5000000,
10000000, 20000000, 30000000, 50000000,
]
this.createStatusBarDomStyle()
this.createStatusBarDomElement()
}
/**
* 创建dom元素
*/
createStatusBarDomElement() {
this.divDom = document.createElement('div')
this.divDom.id = 'statusBarDomElement'
const performaceDom = document.createElement('div')
performaceDom.id = 'performaceDom'
this.divDom.appendChild(performaceDom)
const otherContainer = document.createElement('div')
otherContainer.id = 'otherContainer'
this.divDom.appendChild(otherContainer)
const langLatDom = document.createElement('span')
langLatDom.id = 'langLatDom'
otherContainer.appendChild(langLatDom)
const headingPitchCameraScleDom = document.createElement('span')
headingPitchCameraScleDom.id = 'headingPitchCameraScleDom'
otherContainer.appendChild(headingPitchCameraScleDom)
const scaleBarDom = document.createElement('div')
scaleBarDom.id = 'scaleBarDom'
otherContainer.appendChild(scaleBarDom)
this.el.style.position = 'relative'
this.el.appendChild(this.divDom)
this.setLangLatDomInnerHTML()
this.setHeadingPitchCameraScleDom()
this.getLongAndLat()
this.performanceDisplay = new PerformanceDisplay()
this.viewer.scene.camera.changed.addEventListener(this.getHeadingPitchCamera.bind(this))
this.viewer.scene.postRender.addEventListener(this.showPerformance.bind(this))
}
showPerformance() {
this.performanceDisplay.update(document.getElementById('performaceDom'))
}
createStatusBarDomStyle() {
let style = document.getElementById('StatusBarDomStyle')
if (!style) {
style = document.createElement('style')
style.id = 'StatusBarDomStyle'
const css = /*css*/ `
#statusBarDomElement{
position: absolute;
bottom:0;
width:100%;
height:26px;
color:#fff;
overflow:hidden;
font-size:14px;
line-height:40px;
background-color:rgba(58,58,58,0.8);
z-index:100;
display:flex;
align-items:center;
justify-content: space-between;
padding:0 15px;
box-sizing:border-box;
}
#otherContainer{
display:flex;
align-items:center;
}
#performaceDom{
color:#0f0;
}
#scaleBarDom{
font-size:12px;
text-align:center;
position:relative;
line-height:1.5em;
}
#scaleBarDom::after{
content: "";
position: absolute;
width: 100%;
height: 10px;
border: 1px solid #fff;
border-top: none;
left: 0;
bottom: 0;
}
`
const cssText = document.createTextNode(css)
style.appendChild(cssText)
document.body.appendChild(style)
}
}
setLangLatDomInnerHTML() {
this.divDom.querySelector('#langLatDom').innerHTML = `
<span>经度:${this.longitude} </span>
<span>经度:${this.latitude} </span>`
}
setHeadingPitchCameraScleDom() {
this.divDom.querySelector('#headingPitchCameraScleDom').innerHTML = `
<span>距地面:${this._cameraHeight} </span>
<span>方向:${this.pitch} </span>
<span>俯仰角:${this.heading} </span>`
}
computedScaleLineWidth(surfaceDistance) {
//定义比例尺最大的宽度100px
let maxScaleLineWidth = 100
let distance
for (let i = this.scaleList.length - 1; i >= 0; --i) {
if (this.scaleList[i] / surfaceDistance < maxScaleLineWidth) {
distance = this.scaleList[i]
break
}
}
if (distance) {
const label = distance >= 1000 ? distance / 1000 + ' km' : distance + ' m'
const scaleLineWidth = (distance / surfaceDistance) | 0
this.setScaleLineWidth(label, scaleLineWidth)
}
}
setScaleLineWidth(label, scaleLineWidth) {
const scaleBarDom = this.divDom.querySelector('#scaleBarDom')
scaleBarDom.innerText = label
scaleBarDom.style.width = scaleLineWidth + 'px'
}
getLongAndLat() {
this._handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas)
this._handler.setInputAction((movement) => {
const endPosition = movement.endPosition
const cartesian = this.viewer.scene.camera.pickEllipsoid(
endPosition,
this.viewer.scene.globe.ellipsoid,
)
if (Cesium.defined(cartesian)) {
const cartographic = Cesium.Cartographic.fromCartesian(cartesian)
this.longitude = Cesium.Math.toDegrees(cartographic.longitude).toFixed(5)
this.latitude = Cesium.Math.toDegrees(cartographic.latitude).toFixed(5)
this.setLangLatDomInnerHTML()
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE)
}
getHeadingPitchCamera() {
const scene = this.viewer.scene
const globe = scene.globe
const left = scene.camera.getPickRay(
new Cesium.Cartesian2((this.width / 2) | 0, this.height - 1),
)
const right = scene.camera.getPickRay(
new Cesium.Cartesian2((1 + this.width / 2) | 0, this.height - 1),
)
const leftPosition = globe.pick(left, scene)
const rightPosition = globe.pick(right, scene)
if (leftPosition && rightPosition) {
const geodesic = new Cesium.EllipsoidGeodesic()
const leftCartographic = globe.ellipsoid.cartesianToCartographic(leftPosition)
const rightCartographic = globe.ellipsoid.cartesianToCartographic(rightPosition)
geodesic.setEndPoints(leftCartographic, rightCartographic)
const surfaceDistance = geodesic.surfaceDistance
this.computedScaleLineWidth(surfaceDistance)
this.setHeadingPitchCameraScleDom()
}
const cameraHeight = this.viewer.camera.positionCartographic.height
this._cameraHeight =
cameraHeight < 1000
? cameraHeight.toFixed(2) + 'm'
: (cameraHeight / 1000).toFixed(2) + 'km'
this.pitch = this.viewer.scene.camera.pitch.toFixed(4)
this.heading = this.viewer.scene.camera.heading.toFixed(4)
}
destroy() {
this.viewer.scene.camera.changed.removeEventListener(this.getHeadingPitchCamera.bind(this))
this.viewer.scene.postRender.removeEventListener(this.showPerformance.bind(this))
this._handler?.destroy()
this.performanceDisplay.destroy()
this.divDom?.remove()
document.body.removeChild(document.getElementById('StatusBarDomStyle'))
// @ts-ignore
this.viewer = null
return Cesium.destroyObject(this)
}
}
使用方式
导入
import StatusBar from '@/cesium/status-bar/StatusBar';
viewer = new Cesium.Viewer('map', {
});
// 创建
// 状态栏组件
const statusbar = new StatusBar(viewer, document.getElementById('map'));
// 销毁,不使用时调用destroy方法销毁
// statusbar.destroy()

浙公网安备 33010602011771号