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.
297 lines
9.1 KiB
297 lines
9.1 KiB
2 years ago
|
<template>
|
||
|
|
||
|
<div id="videoWrapper">
|
||
|
<canvas ref="videoCanvas" id="videoCanvas" :width="canvasWidth" :height="canvasHeight">
|
||
|
</canvas>
|
||
|
<video ref="videoPlayer" id="videoPlayer" autoplay muted
|
||
|
@loadedmetadata="changeVideoCanvasSize" @mouseover="mouseOverVideo" @mouseout="mouseOutVideo"
|
||
|
@mousedown="mouseDownVideo">
|
||
|
</video>
|
||
|
<div v-for="item in labelList" class="labels" :key="item.id" :style="`top:${canvasHeight*item.canvasTopRatio}px;left:${canvasWidth*item.canvasLeftRatio}px`">
|
||
|
<div class="labels-item" @click="test(item.id)">
|
||
|
<!-- <div class="labels-item" v-if="item.inFlag"> -->
|
||
|
<img src="@/assets/images/dialog.png" width="80" height="50" alt="">
|
||
|
<span>{{item.name}}</span>
|
||
|
</div>
|
||
|
</div>
|
||
|
</div>
|
||
|
</template>
|
||
|
|
||
|
<script setup lang='ts'>
|
||
|
////@ts-nocheck
|
||
|
import { ref, h, onMounted, getCurrentInstance, ComponentInternalInstance, onUnmounted,watch } from "vue";
|
||
|
import * as markLabelApi from '@/axios/cameraMark/markLabelApi';
|
||
|
import * as markSearchApi from '@/axios/core/markSearchApi';
|
||
|
import { useStore } from '@/store/index';
|
||
|
import { apiUrl } from "@/axios";
|
||
|
import {storeToRefs} from 'pinia';
|
||
|
import Msg from "@/utils/message";
|
||
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
||
|
let piniaStore = useStore();
|
||
|
let player = <HTMLVideoElement>document.querySelector('#videoPlayer')
|
||
|
let canvas = <HTMLCanvasElement>document.querySelector('#videoCanvas')
|
||
|
let canvasWidth = ref(0)
|
||
|
let canvasHeight = ref(0)
|
||
|
let curSelectKey = storeToRefs(piniaStore).curSelectKey
|
||
|
let cameraMap = storeToRefs(piniaStore).cameraMap
|
||
|
let webRtcServer: any = ref()
|
||
|
let isActiveChoose = ref(false)
|
||
|
let labelList=ref<any[]>([])
|
||
|
onMounted(() => {
|
||
|
{
|
||
|
player = <HTMLVideoElement>document.querySelector('#videoPlayer');
|
||
|
canvas = <HTMLCanvasElement>document.querySelector('#videoCanvas');
|
||
|
// loadTreeData();
|
||
|
loadVideoPlayer();
|
||
|
loadVideoCanvas();
|
||
|
|
||
|
}
|
||
|
})
|
||
|
watch(curSelectKey,(newVal,oldVal)=>{
|
||
|
switchCamera(newVal)
|
||
|
})
|
||
|
function test(id:number){
|
||
|
console.log(id,"id++++++++++++");
|
||
|
|
||
|
markLabelApi.Delete({id}).then((res:any)=>{
|
||
|
console.log(res.data);
|
||
|
if(res.data.code==200){
|
||
|
let msg=res.data.data==true?"删除成功":"删除失败"
|
||
|
if(res.data.data){
|
||
|
labelList.value=labelList.value.filter((element:any) => {
|
||
|
return element.id!=id
|
||
|
});
|
||
|
Msg.success("删除成功")
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
Msg.error("删除失败")
|
||
|
})
|
||
|
}
|
||
|
function loadVideoPlayer() {
|
||
|
let elmId = 'videoPlayer';
|
||
|
let url = apiUrl.WebRtcUrl;
|
||
|
webRtcServer.value = new WebRtcStreamer(elmId, url);
|
||
|
}
|
||
|
function loadVideoCanvas() {
|
||
|
window.addEventListener('resize', () => {
|
||
|
changeVideoCanvasSize();
|
||
|
});
|
||
|
}
|
||
|
function changeVideoCanvasSize() {
|
||
|
canvasWidth.value = player.clientWidth;
|
||
|
canvasHeight.value = player.clientHeight;
|
||
|
}
|
||
|
function mouseOverVideo() {
|
||
|
// console.log("移入");
|
||
|
|
||
|
if (!isActiveChoose.value) return;
|
||
|
player.classList.add('activeChoose');
|
||
|
}
|
||
|
function mouseOutVideo() {
|
||
|
// console.log("移除");
|
||
|
|
||
|
if (!isActiveChoose) return;
|
||
|
player.classList.remove('activeChoose');
|
||
|
}
|
||
|
function mouseDownVideo(e: MouseEvent) {
|
||
|
if (!isActiveChoose.value) return;
|
||
|
let cameraId = cameraMap.value.get(curSelectKey.value).id;
|
||
|
let name = 'markLabel-' + Date.now();
|
||
|
let videoWidth = player.videoWidth | 1920;
|
||
|
let videoHeight = player.videoHeight | 1080;
|
||
|
let canvasWidth = player.clientWidth;
|
||
|
let canvasHeight = player.clientHeight;
|
||
|
let canvasLeft = e.offsetX;
|
||
|
let canvasTop = e.offsetY;
|
||
|
let canvasLeftRatio = canvasLeft / canvasWidth;
|
||
|
let canvasTopRatio = canvasTop / canvasHeight;
|
||
|
let entity = {
|
||
|
CbCameraId: cameraId,
|
||
|
Name: name,
|
||
|
VideoWidth: videoWidth,
|
||
|
VideoHeight: videoHeight,
|
||
|
CanvasLeftRatio: canvasLeftRatio,
|
||
|
CanvasTopRatio: canvasTopRatio
|
||
|
}
|
||
|
console.log(entity);
|
||
|
markLabelApi.AddReturnId({
|
||
|
'entity': entity
|
||
|
}).then((res: any) => {
|
||
|
let markLabelId: number = res.data.data;
|
||
|
console.log(markLabelId);
|
||
|
|
||
|
if (markLabelId <= 0) return;
|
||
|
markSearchApi.ActivateMarkLabel({
|
||
|
'cameraId': cameraId,
|
||
|
'markLabelId': markLabelId
|
||
|
}).then((res: any) => {
|
||
|
let ret: boolean = res.data.data;
|
||
|
});
|
||
|
})
|
||
|
}
|
||
|
function activateChoose() {
|
||
|
if (curSelectKey.value.length == 0) return;
|
||
|
isActiveChoose.value = true;
|
||
|
}
|
||
|
function deactivateChoose() {
|
||
|
if (curSelectKey.value.length == 0) return;
|
||
|
isActiveChoose.value = false;
|
||
|
}
|
||
|
function switchCamera(cameraId: string) {
|
||
|
console.log('camera switch.');
|
||
|
|
||
|
// step1, get camera obj.
|
||
|
console.log('get camera obj.');
|
||
|
let cameraObj = cameraMap.value.get(cameraId);
|
||
|
if (!cameraObj) {
|
||
|
console.log('camera obj not found.');
|
||
|
return;
|
||
|
}
|
||
|
// object to proxy, ?
|
||
|
console.log(cameraObj, '111111');
|
||
|
|
||
|
// step2, get camera rtsp url.
|
||
|
console.log('get camera rtsp url.');
|
||
|
let rtspUrl = getRtspUrl(cameraObj);
|
||
|
|
||
|
// step3, connect webrtc-steamer.
|
||
|
console.log('connect webrtc-steamer.');
|
||
|
webRtcServer.value.disconnect();
|
||
|
webRtcServer.value.connect(rtspUrl);
|
||
|
|
||
|
// step4, active camera searcher.
|
||
|
markSearchApi.IsExistsSearcher({
|
||
|
'cameraId': cameraObj.id
|
||
|
}).then((res: any) => {
|
||
|
let flag: boolean = res.data.data;
|
||
|
if (!flag) {
|
||
|
console.log('not exist searcher.');
|
||
|
markSearchApi.ActiveSearcher({
|
||
|
'cameraId': cameraObj.id
|
||
|
}).then((res: any) => {
|
||
|
let flag: boolean = res.data.data;
|
||
|
console.log('activate searcher : ', flag);
|
||
|
if (flag) {
|
||
|
console.log('load camera labels');
|
||
|
getLabel(cameraObj.id)
|
||
|
loadMarkLabelsByLoop(cameraObj);
|
||
|
|
||
|
}
|
||
|
});
|
||
|
} else {
|
||
|
console.log('load camera labels');
|
||
|
getLabel(cameraObj.id)
|
||
|
loadMarkLabelsByLoop(cameraObj);
|
||
|
}
|
||
|
})
|
||
|
|
||
|
// step5, load camera labels.
|
||
|
}
|
||
|
function getRtspUrl(cameraObj: any): string {
|
||
|
// 模拟 onvif
|
||
|
return "rtsp://admin:hk123456@192.168.1.65:554/Streaming/Channels/101?transportmode=unicast&profile=Profile_1";
|
||
|
}
|
||
|
function getLabel(cbCameraId:string|number){
|
||
|
markLabelApi.GetList({cbCameraId}).then((res:any)=>{
|
||
|
|
||
|
if(res.data.code==200){
|
||
|
console.log(res,'res');
|
||
|
labelList.value=res.data.data
|
||
|
}
|
||
|
})
|
||
|
}
|
||
|
function loadMarkLabelsByLoop(cameraObj: any, ms: number = 1000) {
|
||
|
if (curSelectKey.value !== cameraObj.id) {
|
||
|
console.log('load camera labels end.');
|
||
|
return;
|
||
|
}
|
||
|
loadMarkLabels(cameraObj);
|
||
|
setTimeout(() => {
|
||
|
loadMarkLabelsByLoop(cameraObj, ms);
|
||
|
}, ms);
|
||
|
}
|
||
|
function loadMarkLabels(cameraObj: any) {
|
||
|
markSearchApi.GetMarkLabelCalcResultList({
|
||
|
'cameraId': cameraObj.id
|
||
|
}).then((res: any) => {
|
||
|
let list: Array<any> = res.data.data;
|
||
|
list.forEach((element:any) => {
|
||
|
labelList.value.forEach((item:any,index:number) => {
|
||
|
if(element.id==item.id){
|
||
|
labelList.value[index].canvasLeftRatio=element.canvasLeftRatio
|
||
|
labelList.value[index].canvasTopRatio=element.canvasTopRatio
|
||
|
labelList.value[index].inFlag=element.inFlag
|
||
|
|
||
|
}
|
||
|
|
||
|
});
|
||
|
});
|
||
|
// console.log(labelList);
|
||
|
|
||
|
// drawMarkLabels(list);
|
||
|
});
|
||
|
}
|
||
|
function drawMarkLabels(markLabels: Array<any>) {
|
||
|
let ctx = canvas.getContext('2d');
|
||
|
if (!ctx) return;
|
||
|
ctx.clearRect(0, 0, canvasWidth.value, canvasHeight.value);
|
||
|
for (let markLabel of markLabels) {
|
||
|
if (!markLabel.inFlag) continue;
|
||
|
let x = Math.round(canvasWidth.value * markLabel.canvasLeftRatio);
|
||
|
let y = Math.round(canvasHeight.value * markLabel.canvasTopRatio);
|
||
|
x = canvasWidth.value * markLabel.canvasLeftRatio;
|
||
|
y = canvasHeight.value * markLabel.canvasTopRatio;
|
||
|
// console.log(markLabel);
|
||
|
ctx.beginPath();
|
||
|
ctx.arc(x, y, 5, 0, 2 * Math.PI);
|
||
|
ctx.fillStyle = "red";
|
||
|
ctx.fill();
|
||
|
ctx.closePath();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
onUnmounted(() => {
|
||
|
{
|
||
|
console.log('beforeUnmount.');
|
||
|
// 释放 webRtcServer
|
||
|
if (!webRtcServer.value) return;
|
||
|
console.log(123);
|
||
|
webRtcServer.value.disconnect();
|
||
|
webRtcServer.value = null;
|
||
|
}
|
||
|
})
|
||
|
</script>
|
||
|
|
||
|
<style scoped lang='less'>
|
||
|
#videoWrapper {
|
||
|
height: 100vh;
|
||
|
position: relative;
|
||
|
overflow: hidden;
|
||
|
#videoCanvas {
|
||
|
position: absolute;
|
||
|
}
|
||
|
|
||
|
#videoPlayer {
|
||
|
height: 100%;
|
||
|
width: 100%;
|
||
|
object-fit: fill;
|
||
|
}
|
||
|
.labels{
|
||
|
position: absolute;
|
||
|
top: 0;
|
||
|
left: 0;
|
||
|
transform: translate(-50%,-50%);
|
||
|
z-index: 2;
|
||
|
.labels-item{
|
||
|
position: relative;
|
||
|
span{
|
||
|
position: absolute;
|
||
|
top: 50%;
|
||
|
left: 50%;
|
||
|
transform: translate(-50%,-50%);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
</style>
|