1. 需求描述
在视频中选定部分区域,然后将左上角坐标百分比和选定区域宽高所占百分比传给后端
2. 实现思路
- 播放 flv 格式视频
- 点击“截取”按钮,将视频当前画面截取为一张图片并回显图片,
- 使用 Cropper 插件截取图片部分区域(可以获取到截取图片左上角点坐标和截取部分的宽高)
3. 效果图展示
4. 代码
<template>
<el-dialog
title="标定识别区域"
:visible.sync="dialogVisible"
width="50%"
@close="closeHandler"
append-to-body
:close-on-click-modal="false"
>
<video
v-show="!imgSrc.length"
id="videoElement"
class="video-component"
ref="videoElement"
controls
muted
>
不支持
</video>
<div v-if="!!imgSrc.length" class="imgBox">
<img id="image" :src="imgSrc" alt="" />
</div>
<div class="btns">
<el-button :disabled="!!imgSrc.length" type="primary" size="mini" @click="interceptHandler">
截图
</el-button>
<el-button :disabled="!imgSrc.length" type="primary" size="mini" @click="imgSrc = ''">
重新截图
</el-button>
<el-button :disabled="!imgSrc.length" type="primary" size="mini" @click="sureHandler">
确定
</el-button>
</div>
</el-dialog>
</template>
<script>
import flvjs from 'flv.js'
import html2canvas from 'html2canvas'
import Cropper from 'cropperjs'
import 'cropperjs/dist/cropper.css'
import { updateRectf } from '@/api/video-intelligent-analysis.js'
export default {
name: 'SignAreaDialog',
components: {},
data() {
return {
dialogVisible: false,
imgSrc: '',
screenshotInfo: {
x: 0,
y: 0,
width: 0,
height: 0
},
rowData: {},
pRowData: {}
}
},
computed: {},
watch: {
imgSrc: {
handler(val) {
let _this = this
setTimeout(() => {
if (!val) return
const image = document.getElementById('image')
const cropper = new Cropper(image, {
scalable: false,
zoomable: false,
zoomOnWheel: false,
crop(event) {
Object.keys(_this.screenshotInfo).forEach((key) => {
_this.screenshotInfo[key] = event.detail[key] < 0 ? 0 : event.detail[key]
})
}
})
}, 50)
},
deep: true,
immediate: true
}
},
mounted() {},
created() {},
methods: {
open(type, rowData, pRowData, videoUrl) {
this.rowData = rowData
this.pRowData = pRowData
setTimeout(() => {
if (flvjs.isSupported()) {
var videoElement = document.getElementById('videoElement')
var flvPlayer = flvjs.createPlayer({
type: 'flv',
isLive: true,
url: videoUrl
})
flvPlayer.attachMediaElement(videoElement)
flvPlayer.load()
flvPlayer.play()
}
}, 50)
this.dialogVisible = true
},
interceptHandler(event, ownerInstance) {
html2canvas(document.getElementById('videoElement'), {
backgroundColor: null,
useCORS: true
}).then((canvas) => {
let url = canvas.toDataURL('image/png')
this.imgSrc = url
})
},
sureHandler() {
const container = document.querySelector('.cropper-container')
const containerWidth = container.offsetWidth
const containerHeight = container.offsetHeight
let params = {
sfbh: this.pRowData.id,
znfxbh: this.rowData.znfxbh,
rectfX: (((this.screenshotInfo.x * 1) / containerWidth) * 1).toFixed(7) * 1,
rectfY: (((this.screenshotInfo.y * 1) / containerHeight) * 1).toFixed(7) * 1,
rectfW: (((this.screenshotInfo.width * 1) / containerWidth) * 1).toFixed(7) * 1,
rectfH: (((this.screenshotInfo.height * 1) / containerHeight) * 1).toFixed(7) * 1
}
for (let key in params) {
if (params[key] > 1) params[key] = 1
}
updateRectf(params).then((res) => {
this.$common.CheckCode(res, '标定成功', () => {
this.dialogVisible = false
this.$emit('update')
})
})
},
closeHandler() {
this.imgSrc = ''
document.getElementById('videoElement').pause()
for (let key in this.screenshotInfo) {
this.screenshotInfo[key] = 0
}
}
}
}
</script>
<style lang='scss' scoped>
::v-deep .el-dialog__body {
// display: flex;
// justify-content: center;
padding: 20px !important;
}
#videoElement {
width: 100%;
}
// ::v-deep .cropper-bg {
// width: 100% !important;
// }
.btns {
margin-top: 10px;
text-align: right;
}
</style>
cropperjs 参数配置文档 cropperjs npm官方地址
|