| | |
| | | <div class="heatCamera"> |
| | | <div class="camera"> |
| | | <nav class="header-nav"> |
| | | |
| | | <div class="toolbar"> |
| | | <el-date-picker @change="timeChange" v-model="timeRange" value-format="yyyy-MM-dd HH:mm:ss" type="datetimerange" range-separator="至" start-placeholder="开始日期" |
| | | end-placeholder="结束日期" size="small"></el-date-picker> |
| | | <el-button type="primary" size="small">查询</el-button> |
| | | </div> |
| | | <div class="logo"> |
| | | <img src="image/basic.png" alt /> |
| | | </div> |
| | | <div class="toolbar"> |
| | | <el-radio-group v-model="dimension" size="mini"> |
| | | <el-radio-button :label="1">热力图</el-radio-button> |
| | | <el-radio-button :label="2">轨迹图</el-radio-button> |
| | | </el-radio-group> |
| | | <el-select |
| | | v-model="camera" |
| | | filterable |
| | | size="mini" |
| | | style="width:200px;" |
| | | placeholder="请选择摄像机" |
| | | value-key="id" |
| | | > |
| | | <el-option |
| | | v-for="item in allCameras" |
| | | style="font-size:12px" |
| | | :key="item.id" |
| | | :label="item.name" |
| | | :value="item" |
| | | :title="item.name" |
| | | ></el-option> |
| | | </el-select> |
| | | |
| | | <el-date-picker |
| | | v-model="timeRange" |
| | | value-format="yyyy-MM-dd HH:mm:ss" |
| | | type="datetimerange" |
| | | range-separator="至" |
| | | start-placeholder="开始日期" |
| | | end-placeholder="结束日期" |
| | | size="mini" |
| | | ></el-date-picker> |
| | | <el-button |
| | | type="primary" |
| | | @click="postCameraData" |
| | | :loading="querying" |
| | | size="mini" |
| | | icon="el-icon-search" |
| | | >查询</el-button> |
| | | </div> |
| | | </nav> |
| | | |
| | | |
| | | <div class="img-area" ref="heatMap"> |
| | | <!-- <el-image src="/timg.jpg" fit="contain" ref="img"></el-image> --> |
| | | <el-image :src="`${publicPath}images/login-net.png`" fit="contain" ref="img"></el-image> |
| | | <span |
| | | class="dot" |
| | | v-for="(item,index) in dots" |
| | | :style="{top:item.y+'px',left: item.x+'px'}" |
| | | :key="'d'+index" |
| | | ></span> |
| | | <el-image :src="baseImg" fit="contain" ref="img"> |
| | | <div slot="error" class="image-slot"></div> |
| | | </el-image> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </template> |
| | | <script> |
| | | import Heatmap from 'heatmap.js'; |
| | | import {getHeatCameraData} from '@/api/heatCamera' |
| | | import { getHeatCameraData } from '@/api/heatCamera' |
| | | import { getCamerasByServer } from '@/api/pollConfig' |
| | | import { getPersonData } from './api' |
| | | |
| | | export default { |
| | | data(){ |
| | | return { |
| | | publicPath: process.env.BASE_URL, |
| | | timeRange: [new Date(2020, 8, 20, 8), new Date(2020, 9, 20, 8)], |
| | | params: { |
| | | cameraIds: ["c6fd8f31-248f-49fc-93e0-dedac889197b","c41a2f34-bd2e-41af-9bc0-51e6dcd03523"], |
| | | startTime: '', |
| | | endTime: '', |
| | | name: "heatCamera", |
| | | computed: { |
| | | baseImg() { |
| | | let imgUrl = ""; |
| | | |
| | | if (this.camera.snapshot_url && this.camera.snapshot_url.length) { |
| | | imgUrl = '/httpImage/' + this.camera.snapshot_url |
| | | } |
| | | |
| | | return imgUrl |
| | | } |
| | | }, |
| | | mounted(){ |
| | | console.log(Heatmap.create) |
| | | setTimeout(()=>{ |
| | | this.mockAsync() |
| | | },2000); |
| | | data() { |
| | | return { |
| | | publicPath: process.env.BASE_URL, |
| | | querying: false, |
| | | dots: [], |
| | | dimension: 1, |
| | | timeRange: [ |
| | | this.$moment().format("YYYY-MM-DD 00:00:00"), |
| | | this.$moment().format("YYYY-MM-DD HH:mm:ss") |
| | | ], |
| | | camera: {}, |
| | | allCameras: [], |
| | | snapshot_url: "", |
| | | heatmapInstance: null, |
| | | } |
| | | }, |
| | | methods:{ |
| | | timeChange(val){ |
| | | console.log(val); |
| | | this.params.startTime = val[0]; |
| | | this.params.endTime = val[1]; |
| | | this.renderHeatMap(this.params) |
| | | }, |
| | | mockAsync(){ |
| | | var config = { |
| | | container: document.querySelector('.img-area'), |
| | | radius: 10, |
| | | maxOpacity: .75, |
| | | minOpacity: 0, |
| | | blur: .75, |
| | | gradient: { |
| | | '.5': 'blue', |
| | | '.8': 'red', |
| | | '0.95': 'white', |
| | | '0.6': 'yellow', |
| | | '0.5': 'green' |
| | | mounted() { |
| | | this.getAllCamera(); |
| | | }, |
| | | methods: { |
| | | getAllCamera() { |
| | | getCamerasByServer().then(rsp => { |
| | | if (rsp && rsp.success) { |
| | | this.allCameras = rsp.data |
| | | } |
| | | |
| | | }) |
| | | }, |
| | | setHeatmapData(sources) { |
| | | if (sources === null || sources.length < 1) { |
| | | return |
| | | } |
| | | var heatmapConfig = { |
| | | container: document.querySelector('.img-area'), |
| | | radius: 20, |
| | | maxOpacity: .55, |
| | | minOpacity: 0, |
| | | blur: .55, |
| | | gradient: { |
| | | '.8': 'yellow', |
| | | '0.95': 'rgba(251, 40, 40, 0.3)', |
| | | '0.6': 'rgba(42, 251, 199, 0.3)', |
| | | //'0.5': 'rgba(2, 119, 251, 0.3)' |
| | | '0.5': 'rgba(2, 251, 251, 0.3)' |
| | | } |
| | | }; |
| | | var data = { |
| | | max: 700, |
| | | var points = { |
| | | max: 300, |
| | | min: 0, |
| | | data: [] |
| | | } |
| | | for (var i = 10; i < 700; i++) { |
| | | var dataPoint = { |
| | | x: Math.floor(Math.random() * i), |
| | | y: Math.floor(Math.random() * i), |
| | | value: Math.floor(Math.random() * i) |
| | | }; |
| | | var dataCenter = { |
| | | x: i, |
| | | y: i, |
| | | value: 30 + i |
| | | } |
| | | data.data.push(dataPoint, dataCenter) |
| | | if (this.heatmapInstance === null) { |
| | | this.heatmapInstance = Heatmap.create(heatmapConfig); |
| | | } else { |
| | | this.heatmapInstance.setData(points); |
| | | } |
| | | //var heatmapInstance = h337.create(config); |
| | | var heatmapInstance = Heatmap.create(config); |
| | | heatmapInstance.setData(data); |
| | | sources.forEach(ele => { |
| | | points.data.push(this.formatPoint(ele)) |
| | | if (this.dimension == 2) { |
| | | this.dots.push(this.formatPoint(ele)) |
| | | } |
| | | }); |
| | | |
| | | //热力图 |
| | | if (this.dimension == 1) { |
| | | this.heatmapInstance.setData(points); |
| | | } |
| | | }, |
| | | renderHeatMap(params){ |
| | | getHeatCameraData(params).then(res=>{ |
| | | debugger |
| | | postCameraData() { |
| | | this.dots = []; |
| | | let params = {}; |
| | | if (!this.camera.id || !this.camera.id.length) { |
| | | this.$message({ |
| | | type: "error", |
| | | message: "请选择一个摄像机" |
| | | }) |
| | | return; |
| | | } |
| | | params.cameraIds = [this.camera.id]; |
| | | params.startDate = this.timeRange[0]; |
| | | params.endDate = this.timeRange[1]; |
| | | |
| | | this.querying = true; |
| | | getPersonData(params).then(rsp => { |
| | | if (rsp && rsp.success) { |
| | | this.setHeatmapData(rsp.data.result) |
| | | } |
| | | this.querying = false |
| | | }).catch(() => { |
| | | this.querying = false |
| | | }) |
| | | }, |
| | | formatPoint(data) { |
| | | var converters = { |
| | | "default": { |
| | | "scale": 0.66, |
| | | "offsetX": 0, |
| | | "offsetY": 0 |
| | | } |
| | | } |
| | | |
| | | var cv = converters[data.cameraId] ? converters[data.cameraId] : converters["default"] |
| | | |
| | | var topLeft = data.personRect.topLeft |
| | | var bottomRight = data.personRect.bottomRight |
| | | |
| | | // 中心点 |
| | | var dataPoint = { |
| | | //x: ((topLeft.x + bottomRight.x) * cv.scale + cv.offsetX * 2) / 2, |
| | | //y: ((topLeft.y + bottomRight.y) * cv.scale + cv.offsetY * 2) / 2, |
| | | x: ((topLeft.x + bottomRight.x) * cv.scale + cv.offsetX * 2) / 2, |
| | | y: ((bottomRight.y) * cv.scale + cv.offsetY), |
| | | value: data.stayTime |
| | | }; |
| | | if (dataPoint.y > 720) { |
| | | dataPoint.y = 720 |
| | | } |
| | | |
| | | return dataPoint |
| | | } |
| | | |
| | | } |
| | | } |
| | | </script> |
| | | <style lang="scss"> |
| | | .heatCamera{ |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #e9ebf2; |
| | | .header-nav{ |
| | | height: 60px; |
| | | min-width: 1200px; |
| | | background-image: linear-gradient(-180deg, #ffffff 13%, #e9ebf2 100%); |
| | | } |
| | | .toolbar{ |
| | | width: 500px; |
| | | height: 60px; |
| | | //background: rgba(0,0,0,.3); |
| | | position: absolute; |
| | | right: 60px; |
| | | top: 20px; |
| | | text-align: center; |
| | | line-height: 60px; |
| | | z-index: 10; |
| | | .el-date-editor{ |
| | | vertical-align: middle; |
| | | border-radius: 4px 0 0 4px; |
| | | } |
| | | .el-button{ |
| | | vertical-align: middle; |
| | | margin-left: 4px; |
| | | } |
| | | } |
| | | .img-area{ |
| | | margin: 30px auto; |
| | | width: 1200px; |
| | | //position: relative; |
| | | font-size: 0; |
| | | } |
| | | img{ |
| | | display: block; |
| | | } |
| | | |
| | | .heatCamera { |
| | | width: 100%; |
| | | height: 100%; |
| | | background: #e9ebf2; |
| | | .header-nav { |
| | | height: 60px; |
| | | min-width: 1200px; |
| | | background-image: linear-gradient(-180deg, #ffffff 13%, #e9ebf2 100%); |
| | | } |
| | | .toolbar { |
| | | width: 850px; |
| | | height: 60px; |
| | | //background: rgba(0,0,0,.3); |
| | | position: absolute; |
| | | right: 60px; |
| | | top: 20px; |
| | | text-align: center; |
| | | line-height: 60px; |
| | | z-index: 10; |
| | | .el-date-editor { |
| | | vertical-align: middle; |
| | | border-radius: 4px 0 0 4px; |
| | | margin: 0 8px; |
| | | } |
| | | .el-button { |
| | | vertical-align: middle; |
| | | margin-left: 4px; |
| | | } |
| | | } |
| | | .img-area { |
| | | margin: 30px auto; |
| | | width: 1280px; |
| | | height: 720px; |
| | | position: relative; |
| | | font-size: 0; |
| | | background-color: black; |
| | | .dot { |
| | | width: 10px; |
| | | height: 10px; |
| | | background-image: radial-gradient(circle, #04f3ff, #adf7f7, #31e4d3); |
| | | opacity: 0.5; |
| | | border-radius: 50%; |
| | | position: absolute; |
| | | z-index: 1000; |
| | | } |
| | | } |
| | | img { |
| | | display: block; |
| | | } |
| | | } |
| | | </style> |