实现目标:获取监控树,其中监控树只有叶子节点才有多选框,点击多选框在地球上添加多个图标,左击不同的图标出现对应的实时监控画面。监控树的数据以及实时监控的画面都是通过与后端对接接口获取的。
添加一个图标上图并点击出现弹窗可参考:Cesium添加图标后点击该图标出现弹窗的具体实现方法_刚刚好ā的博客-CSDN博客_cesium
同时添加多个图标的重点是:获取到数组后,将数组传递给cesium添加图标的方法,并对其进行处理,获取对应的经纬度,进而上图。
vue文件的template中:
监控树:
<div class="tree-con-tree">
<el-tree
:data="monitorTreeData"
:props="defaultProps"
show-checkbox
node-key="name"
:default-expand-all="false"
:expand-on-click-node="false"
ref="monitorTreeBox"
@check-change="monitorTreeCheckedChange"
:filter-node-method="filterNode"
>
</el-tree>
</div>
视频为m3u8格式:具体的引入及播放可参考vue中播放m3u8格式实时监控画面(取流)--调用后端接口_刚刚好ā的博客-CSDN博客
<!-- 视频弹窗 -->
<div class="project-info" id="videoModel" ref="videoModel">
<div class="projtct-title">{{ monitorName }}</div>
<div class="project-close" @click="closeInfo"></div>
<div class="project-info-content">
<div id="videobox"></div>
</div>
</div>
vue文件的data中:
import { monitorTree, subMonitorPointPage, videoPreview } from '@/api/xx/xxxr'
import { videoAddIconMarker, videoRemove, videoDialog, removeVideoDialog, setVideoHandler } from '@/earth/xxxx/xxxx.js'
import videojs from 'video.js'
import 'videojs-contrib-hls'
data() {
return {
monitorTreeData: [], // 监控树
defaultProps: {
children: 'children',
label: 'name',
value: 'indexCode',
emitPath: false,
checkStrictly: true,
expandTrigger: 'hover',
disabled: 'disabled'
},
inputVal: '',
latLonData: [], // 存放经纬度的数组
indexCodeCamera: '', // 子节点id
srcPath: '', // 视频播放链接
monitorName: '' // 监控点名称
}
},
在data之前定义这两变量,方便后面的使用
let myVideo = null
let entVideo = null
vue文件的mouted:初始该界面时就加载监控树
mounted() {
this.getMonitorTree()
},
vue文件的watch:
watch: {
// 取消勾选时移除图标
beforeDestroy() {
videoRemove() // 清除图标
},
vue文件的methods中:
获取监控树,设置只有叶子节点可勾选
// 获取监控树
getMonitorTree() {
monitorTree().then((res) => {
if (res.status == 200) {
this.setMonitorData(res.data.data.children[0].children)
} else {
this.$message.warning('请稍后再试')
}
})
},
// 设置只有叶子结点可勾选
setMonitorData(data) {
let nowdata = data
nowdata.forEach((item) => {
setData(item)
})
this.monitorTreeData = nowdata
function setData(data) {
if (data.children.length == 0) {
data.disabled = false
} else {
data.disabled = true
data.children.forEach((item) => {
setData(item)
})
}
}
},
勾选多选框图层改变:
videoAddIconMarker为添加多个图标的方法,此时将获取的数组进行传递,方便在js文件中的此方法获取到相应的经纬度。同时设置监听,来监控鼠标左击的变化。
monitorTreeCheckedChange(data, checked) {
if (checked) {
if (data) {
// 最终一层节点数据获取--数据格式为表单
let monitorForm = new FormData()
monitorForm.append('regionIndexCode', data.indexCode)
monitorForm.append('treeCode', 0)
monitorForm.append('pageNo', 1)
monitorForm.append('pageSize', 1000)
// 调用接口--获取叶子节点的数据
subMonitorPointPage(monitorForm).then((res) => {
if (res.status == 200) {
let newArr = res.data.data.list
videoAddIconMarker(newArr, this.iconClickFunc)
} else {
this.$message.warning('请稍后再试')
}
})
} else {
this.monitorData = []
}
// // 设置监听
setVideoHandler()
} else {
videoRemove()
this.closeInfo()
}
},
点击出现弹窗:
// 点击弹窗样式
iconClickFunc(entity) {
// 调用点击出现弹窗方法
// console.log(entity)
if (entVideo && entity.id == entVideo.id) {
this.closeInfo()
} else {
if (entity) {
entVideo = entity
entVideo.billboard.image = require('@/assets/images/xxxx.png')
}
// 修改实体样式
this.showVideoDiv(entity.id, entity.name, entity.position._value)
}
},
视频弹窗:
// 视频弹窗显示
showVideoDiv(id, name, position) {
//动态生成video
let doc = document.getElementById('videobox')
let dd = document.createElement('div')
dd.innerHTML = `<video
id="myVideoPlay"
class="video-js vjs-default-skin vjs-big-play-centered"
controls
preload="auto"
width="388"
height="189"
data-setup="{}"
></video>`
doc.appendChild(dd)
this.monitorName = name
this.srcPath = ''
this.indexCodeCamera = id
let param = {
cameraIndexCode: this.indexCodeCamera
}
// 获取摄影监控实时画面
videoPreview(param).then((res) => {
if (res.status == 200) {
this.srcPath = res.data.data.url
console.log(this.srcPath)
setTimeout(() => {
if (myVideo) {
myVideo.dispose()
myVideo = null
}
myVideo = videojs('myVideoPlay', {
bigPlayButton: true,
textTrackDisplay: false,
posterImage: false,
errorDisplay: false
})
myVideo.src(this.srcPath)
myVideo.play()
// myVideo.pause();
})
} else {
this.$message.warning('请稍后再试')
}
videoDialog('videoModel', position, 'Cartesian3')
})
},
// 关闭信息弹窗
closeInfo() {
if (myVideo) {
myVideo.dispose()
myVideo = null
}
if (entVideo) {
entVideo.billboard.image = require('@/assets/images/xxx.png')
entVideo = null
}
// 调用关闭弹窗方法
removeVideoDialog()
},
// 视频播放
playVideo(row) {
// 将接受的值赋值给src
this.videoUrl = row.videoUrl
}
}
添加图标的js文件中:
添加图标的方法是重点,这里将传递来的数组进行遍历,获取其对应的经纬度。
let entArr = [] // 图标
let dialogBox = [] //点击图标出现的信息窗
let dialogBoxPreRenderListener = null; // cesium渲染监听
let handler = null // 鼠标左击事件监听
// 添加图标
function videoAddIconMarker (arr, clickFunc) {
arr.forEach(item => {
if (item.longitude > 0 && item.latitude > 0) {
let videoEntity = viewer.entities.add({
id: item.cameraIndexCode,
name: item.name,
position: Cesium.Cartesian3.fromDegrees(item.longitude, item.latitude),
billboard: {
// 图像地址,URI或Canvas的属性
image: require('@/assets/images/xxxx.png'),
width: 50,
height: 50,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
}
});
entArr.push(videoEntity)
if (clickFunc) {
videoEntity['videoClick'] = clickFunc;
}
}
})
}
// 移除所有图标
function videoRemove () {
if (entArr.length > 0) {
entArr.forEach((item) => {
viewer.entities.remove(item)
})
}
entArr = []; // 清空数组
removeHandler() // 移除监听
}
// 点击图标添加信息窗
function videoDialog (videoId, videoPosition, videoType) {
const videoBox = document.getElementById(videoId);
videoBox.style.display = 'block';
dialogBox.push({
video: videoBox,
videoPosition: videoPosition,
videoType: videoType
})
if (dialogBoxPreRenderListener) {
return;
} else {
dialogBoxPreRenderListener = viewer.scene.preRender.addEventListener(function () {
dialogBox.forEach(item => {
let elWidth = item.video.offsetWidth - 700;
let elHeight = item.video.offsetHeight - 70;
const scratch = new Cesium.Cartesian2();
let position = null;
if (item.videoType == 'Cartesian3') {
position = item.videoPosition;
} else if (item.videoType == 'LonLat') {
position = Cesium.Cartesian3.fromDegrees(item.videoPosition[0], item.videoPosition[1], 20);
}
const canvasPosition = viewer.scene.cartesianToCanvasCoordinates(position, scratch);
if (Cesium.defined(canvasPosition)) {
item.video.style.left = canvasPosition.x - elWidth / 2 + 'px';
item.video.style.top = canvasPosition.y - elHeight + 'px'
}
})
})
}
}
// 移除绑定到图标上的弹窗
function removeVideoDialog () {
if (dialogBox && dialogBox.length && dialogBox.length > 0) {
dialogBox.forEach(item => {
item.video.style.display = 'none';
});
dialogBox = [];
}
if (dialogBoxPreRenderListener) {
dialogBoxPreRenderListener()
dialogBoxPreRenderListener = null
}
}
// 设置监听
function setVideoHandler () {
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
let pickedObject = viewer.scene.pick(movement.position);
if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.id) && typeof pickedObject.id.videoClick === 'function') {
pickedObject.id.videoClick(pickedObject.id, movement);
} else if (Cesium.defined(pickedObject) && Cesium.defined(pickedObject.primitive && typeof pickedObject.primitive.videoClick === 'function')) {
pickedObject.primitive.videoClick(pickedObject, movement);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
}
// 移除监听
function removeHandler () {
if (handler) {
handler.destroy();
handler = null
}
}
export { videoAddIconMarker, videoRemove, videoDialog, removeVideoDialog, setVideoHandler };
接口js文件:
// 查询摄像监控树
export function monitorTree (param) {
return request({
url: "/xxx/monitorTree",
method: "post",
headers: {
"Content-Type": "application/json" // 如果写成contentType会报错
},
data: param
});
}
// 获取叶子节点数据
export function subMonitorPointPage (param) {
return request({
url: "/xxxx/subMonitoringPoint",
method: "post",
data: param
});
}
// 取流 ==> 视频应用服务--获取监控点预览取流URL
export function videoPreview (param) {
return request({
url: "/xxxx/videoPreview",
method: "post",
data: param
});
}