ZRender开发2

主页

<MapZrender ref="imgZrender" class="map-zrender" :map-bg="mapBg" :track-list="trackList"
        :configed-cameras="routePoints" @play-video="handlePlayVideo" />

配置页面

<MapZrender ref="imgZrender" class="map-zrender" :map-bg="mapBg" :is-active="isActive"
          :related-cameras="relatedCameras" :configed-cameras="configedCameras" :point-type="pointType"
          :is-config="true" @change-active="changeActive" @add-point="addPoint" @remove-point="removePoint"
          @play-video="handlePlayVideo" />

MapZrender 组件

<template>
  <div class="map-container">
    <!-- 阻止默认的鼠标右键事件 -->
    <div id="map" @contextmenu.prevent></div>

    <!-- 鼠标悬浮提示 -->
    <!-- <div v-show="titleTip" id="tip">{{ titleTip }}</div> -->

    <div v-show="detailList?.length" id="detailList" class="detail-list">
      <el-button type="ghost" icon="h-icon-close" class="btn-close" @click="detailList = []"></el-button>
      <div v-for="(item, index) in detailList" :key="`${item.certificateNumber}_${index}`" class="card">
        <img :src="imgToNgix(item.facePicUrl)" width="92" height="92" @click="handlePreview(item.bkgUrl)"
          @error="handleError" />
        <div class="card__right">
          <div class="field">
            <div class="field-label">时间:</div>
            <div class="field-value">{{ item.faceTime }}</div>
          </div>
          <div class="field">
            <div class="field-label">地点:</div>
            <div class="field-value" :title="item.cameraName">{{ item.cameraName }}</div>
          </div>
          <div class="field">
            <div class="field-label" style="width: 56px;">相似度:</div>
            <div class="field-value" style="width: calc(100% - 56px);">{{ item.similarity || '--' }}%</div>
          </div>
          <div class="field">
            <el-button size="small" @click="handlePlay(item)">预览</el-button>
            <el-button size="small" @click="handlePlayback(item)">回放</el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import * as zrender from 'zrender/dist/zrender'
let zr
export default {
  props: {
    // 背景图片
    mapBg: {
      type: String,
      default: ''
    },
    // 配置状态是否激活
    isActive: {
      type: Boolean,
      default: false
    },
    // 关联点位
    relatedCameras: {
      type: Array,
      default: () => []
    },

    // 已经关联好的点位
    configedCameras: {
      type: Array,
      default: () => []
    },

    // common: 关联点位;marker: 标记拐点
    pointType: {
      type: String,
      default: 'common'
    },

    // 路线轨迹
    trackList: {
      type: Array,
      default: () => []
    },

    // 是否是配置页面
    isConfig: {
      type: Boolean,
      default: false
    }
  },

  data() {
    return {
      container: null,
      containerWidth: 1,
      containerHeight: 1,
      group: null,
      elements: [],
      pointGroup: null,
      lineGroup: null,
      zrBgImg: null, // 背景图片
      titleTip: '',
      popupElement: null,
      positionImg: require('@/assets/images/position.png'),
      cameraIcon: require('@/assets/images/camera.png'),
      posZrImage: null,
      index: 1,
      time: 1000,
      posX: 200,
      posY: 200,
      direction: '',
      requestID: null,
      detailList: [],
      defaultImg: require('@/assets/images/default-person.png'),
    }
  },

  watch: {
    mapBg: {
      handler: function (val) {
        val && this.addMapBg()
      }
    },

    isActive(val) {
      // 设置鼠标浮动样式
      this.zrBgImg?.attr({
        cursor: val ? 'pointer' : 'unset'
      })
    },

    configedCameras: {
      handler: function (val) {
        console.log(val)
        this.batchAddPoints(val)
      }
    },

    trackList: {
      handler: function (val) {
        this.drawLines()
      }
    }
  },


  mounted() {
    this.init()
    this.popupElement = document.getElementById('detailList')

    // this.addPositionIcon(this.posX, this.posY)
    // window.addEventListener('keydown', this.startMove)
    // window.addEventListener('keyup', this.stopMove)
  },

  methods: {
    // startAnimate() {
    //   switch (this.direction) {
    //     case 'ArrowUp':
    //       this.posY -= 0.1
    //       break
    //     case 'ArrowDown':
    //       this.posY += 0.1
    //       break
    //     case 'ArrowRight':
    //       this.posX += 0.1
    //       break
    //     case 'ArrowLeft':
    //       this.posX -= 0.1
    //       break
    //   }
    //   this.posZrImage.attr({
    //     style: {
    //       x: this.posX,
    //       y: this.posY,
    //     },
    //   })
    //   this.requestID = requestAnimationFrame(this.startAnimate)
    // },

    // startMove({ key }) {
    //   if (['ArrowUp', 'ArrowDown', 'ArrowRight', 'ArrowLeft'].includes(key)) {
    //     this.direction = key
    //     cancelAnimationFrame(this.requestID)
    //     this.requestID = requestAnimationFrame(this.startAnimate)
    //   }
    // },
    // stopMove({ key }) {
    //   if (this.direction === key) {
    //     cancelAnimationFrame(this.requestID)
    //   }
    // },
    init() {
      this.container = document.getElementById('map')
      this.containerWidth = this.container.clientWidth
      this.containerHeight = this.container.clientHeight

      // 初始化zrender实例
      zr = zrender.init(this.container)
      // 创建组。Group 是一个容器,可以插入子节点。
      this.group = new zrender.Group()
      zr.add(this.group)

      // 创建组:用于存放监控点
      this.pointGroup = new zrender.Group()
      this.group.add(this.pointGroup)

      // 创建组:用于存放轨迹路线
      this.lineGroup = new zrender.Group()
      this.group.add(this.lineGroup)

      if (this.mapBg) {
        this.addMapBg()
      }

      if (this.configedCameras?.length) {
        this.batchAddPoints(this.configedCameras)
      }

      if (this.trackList?.length) {
        this.drawLines()
      }
    },

    // 添加背景图片
    addMapBg() {
      const img = new Image()
      img.crossOrigin = 'Anonymous'
      img.setAttribute('crossOrigin', 'Anonymous')
      img.src = this.mapBg
      img.onload = () => {
        this.zrBgImg = new zrender.Image({
          style: {
            image: this.mapBg,
            x: 0,
            y: 0,
            width: this.containerWidth,
            height: this.containerHeight,
          },
          z: 1,
          cursor: 'unset',
        })

        this.group.add(this.zrBgImg)
        this.elements.push(this.zrBgImg)

        this.zrBgImg.on('click', data => {
          if (this.isActive) {
            console.log(data, 'zrBgImg clicked')
            const { offsetX, offsetY } = data
            const x = offsetX / this.containerWidth
            const y = offsetY / this.containerHeight

            if (this.pointType === 'marker') {
              // 拐点
              const timeStamp = new Date().getTime()
              this.$emit('add-point', {
                xPoint: x,
                yPoint: y,
                cameraIndexcode: `p${String(timeStamp).substring(9, 13)}`,
                cameraName: `p${String(timeStamp).substring(9, 13)}`,
                color: '#ff0000',
                type: 'marker'
              })
            } else {
              // 监控点撒点
              this.$emit('add-point', {
                xPoint: x,
                yPoint: y,
                cameraIndexcode: this.relatedCameras.map(item => item.value).join(','),
                cameraName: this.relatedCameras.map(item => item.label).join(','),
                color: '#00ff00',
                type: 'common'
              })
            }
          }
        })
      }
    },

    // 添加点位
    addPoint({ x, y, id, cameraName, type, detailList, cameraIndexcode }) {
      let point
      if (type === 'marker') {
        // 绘制圆点
        point = new zrender.Circle({
          shape: {
            cx: x * this.containerWidth,
            cy: y * this.containerHeight,
            r: 5
          },
          style: {
            fill: '#ff0000',
            stroke: '#ff0000',
          },
          z: 3,
          id,
          name: cameraName,
          cursor: 'pointer',
        })
        // point.on('mouseover', data => {
        //   // 添加鼠标悬浮提示
        //   const {
        //     target: {
        //       name: cameraName,
        //       shape: { cx, cy, r },
        //     },
        //   } = data
        //   this.titleTip = cameraName
        //   this.popupElement.style.left = `${cx + r}px`
        //   this.popupElement.style.top = `${cy + r}px`
        // })
      } else {
        point = new zrender.Image({
          style: {
            image: this.cameraIcon,
            x: x * this.containerWidth - 20,
            y: y * this.containerHeight - 46,
            width: 41,
            height: 46,
          },
          z: 3,
          id,
          name: cameraName,
        })

        if (!this.isConfig) {
          point.on('mouseover', data => {
            this.detailList = detailList
            // 添加鼠标悬浮提示
            const {
              target: {
                style: { x, y },
              },
            } = data
            if (this.containerWidth - data.offsetX < 300) {
              this.popupElement.style.left = `${x - 290}px`
            } else {
              this.popupElement.style.left = `${x + 40}px`
            }
            if (this.detailList.length > 1) {
              if (this.containerHeight - data.offsetY < 226) {
                this.popupElement.style.top = `${y - 216}px`
              } else {
                this.popupElement.style.top = `${y + 23}px`
              }
            } else {
              if (this.containerHeight - data.offsetY < 118) {
                this.popupElement.style.top = `${y - 118}px`
              } else {
                this.popupElement.style.top = `${y + 23}px`
              }
            }
          })
          point.on('mouseout', () => {
            // 隐藏鼠标悬浮提示
            // this.titleTip = ''
            // this.detailList = []
          })
          // point.on('click', data => {
          //   console.log(data)
          //   this.$emit('play-back', data)
          // })
        } else {
          point.on('click', data => {
            console.log(data, cameraIndexcode)
            this.$emit('play-video', {
              playType: 'real',
              cameraIndexCode: cameraIndexcode,
              faceTime: '',
              cameraName: cameraName,
              timeStamp: new Date().getTime()
            })
          })
        }
      }
      this.pointGroup.add(point)

      if (this.isConfig) {
        point.on('contextmenu', data => {
          this.$confirm('是否确定删除?', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
          })
            .then(() => {
              const { target: { id } } = data
              this.$emit('remove-point', id)
            })
            .catch(() => {
              this.$message({
                type: 'success',
                message: '已取消删除!',
              })
            })
        })
      }

      let textOffsetY = type === 'marker' ? 30 : 56


      const zrText = new zrender.Text({
        culling: true, // 是否进行裁剪
        style: {
          x: x * this.containerWidth,
          y: y * this.containerHeight - textOffsetY,
          text: cameraName,
          fill: '#ffffff',
          width: 22,
          height: 22,
          align: 'center',
          verticalAlign: 'middle',
          fontFamily: 'HTYPEtest01-Medium',
          fontSize: 16,
          fontWeight: 400,
        },
        z: 4,
      })
      this.pointGroup.add(zrText)
    },

    // 批量添加点位
    batchAddPoints(data) {
      this.pointGroup.removeAll()
      zr.refresh() // 刷新画布,确保removeAll方法生效
      this.$emit('change-active', false)
      this.$nextTick(() => {
        data.forEach(item => {
          this.addPoint(item)
        })
      })
    },

    drawLines() {
      this.lineGroup.removeAll()
      zr.refresh() // 刷新画布,确保removeAll方法生效
      if (this.trackList?.length) {
        this.addPositionIcon(this.trackList[0][0] * this.containerWidth - 16, this.trackList[0][1] * this.containerHeight - 32)

        const points = this.trackList.map(item => {
          return [item[0] * this.containerWidth, item[1] * this.containerHeight]
        })
        // 多边形
        const polyline1 = new zrender.Polyline({
          shape: {
            points,
            smooth: 0,
          },
          style: {
            lineWidth: 5,
            stroke: '#F7B71F',
          },
          z: 2,
        })
        this.lineGroup.add(polyline1)
        this.time = 10000 / (this.trackList.length - 1)
        this.index = 1
        this.animate()
      }
    },

    addPositionIcon(x, y) {
      // 定位图标
      this.posZrImage = new zrender.Image({
        style: {
          image: this.positionImg,
          x,
          y,
          width: 32,
          height: 32,
        },
        z: 5,
      })
      this.lineGroup.add(this.posZrImage)
    },

    // 定位图标沿着轨迹运动
    animate() {
      this.posZrImage
        .animate('style', false)
        .when(this.time, {
          x: this.trackList[this.index][0] * this.containerWidth - 16,
          y: this.trackList[this.index][1] * this.containerHeight - 32,
        })
        .done(() => {
          this.index++
          if (this.index < this.trackList.length) {
            this.animate()
          }
        }).start()
    },

    handlePreview(url) {
      this.$parent.$parent.$parent.handlePreview(url)
    },

    handleError(e) {
      e.target.src = this.defaultImg;
    },

    handlePlay({ cameraIndexCode, faceTime, cameraName }) {
      this.$emit('play-video', {
        playType: 'real',
        cameraIndexCode: cameraIndexCode,
        faceTime: faceTime,
        cameraName: cameraName,
        timeStamp: new Date().getTime()
      })
    },

    handlePlayback({ cameraIndexCode, faceTime, cameraName }) {
      this.$emit('play-video', {
        playType: 'playback',
        cameraIndexCode: cameraIndexCode,
        faceTime: faceTime,
        cameraName: cameraName,
        timeStamp: new Date().getTime()
      })
    },
  }
}
</script>

<style lang="scss" scoped>
.map-container {
  width: 100%;
  height: 100%;
  position: relative;
}

#map {
  width: 100%;
  height: 100%;
  position: relative;
}

#tip {
  position: absolute;
  border: 1px solid #4d4d4d;
  background-color: #fff;
  padding: 4px;
  z-index: 1;
}

.detail-list {
  width: 322px;
  max-height: 280px;
  padding: 15px;
  overflow: auto;
  background-color: #f0f0f0;
  position: absolute;
  z-index: 1;

  .btn-close {
    position: absolute;
    top: 0;
    right: 0;
    width: 24px;
    height: 24px;
    min-width: 24px !important;
    z-index: 2;
  }

  .card {
    width: 100%;
    height: 120px;
    background-color: #ffffff;
    display: flex;
    align-items: center;
    border-radius: 8px;
    padding: 6px;
    // cursor: pointer;

    &:not(:last-child) {
      margin-bottom: 10px;
    }

    // &:hover {
    //   background-color: rgba(255, 255, 255, 0.5);
    // }
    img {
      float: left;
      cursor: pointer;
    }

    &__right {
      width: calc(100% - 98px);
      height: 100px;
      float: left;
      margin-left: 6px;
      display: flex;
      flex-direction: column;
      justify-content: space-evenly;
    }

    .field {
      width: 100%;
      display: flex;
      align-items: center;

      &-label {
        width: 42px;
        font-family: PingFangSC-Regular;
        color: rgba(0, 0, 0, 0.40);
      }

      &-value {
        width: calc(100% - 42px);
        font-family: PingFangSC-Semibold;
        color: #000000;
        // font-weight: 600;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }



  }

  .active-card {
    background-color: rgb(48, 140, 247);
    color: #ffffff;

    &:hover {
      background-color: rgb(48, 140, 247);
    }

    .row-right {
      background: linear-gradient(270deg, rgba(225, 225, 225, 0.2) 18%, rgba(225, 225, 225, 0.2) 99%);
    }
  }
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/889517.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

使用正则表达式删除文本的奇数行或者偶数行

用智谱清言和kimi搜出来的结果都没法在notepad生效&#xff0c;后面在overflow上找到的答案比较靠谱。 查找&#xff1a;^[^\n]*\n([^\n]*) 替换&#xff1a;\1 删除偶数行 查找&#xff1a;^([^\n]*)\n[^\n]* 替换&#xff1a;\1 代码解释 ^&#xff1a;这个符号代表字符…

【Linux】认识Linux内核中进程级别的文件结构体【files_struct】&文件IO模型初步演示

前言 大家好吖&#xff0c;欢迎来到 YY 滴 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Linux》…

输电线路悬垂线夹检测无人机航拍图像数据集,总共1600左右图片,悬垂线夹识别,标注为voc格式

输电线路悬垂线夹检测无人机航拍图像数据集&#xff0c;总共1600左右图片&#xff0c;悬垂线夹识别&#xff0c;标注为voc格式 输电线路悬垂线夹检测无人机航拍图像数据集介绍 数据集名称 输电线路悬垂线夹检测数据集 (Transmission Line Fittings Detection Dataset) 数据集…

centos7.9升级rockylinux8.8

前言 查看centos的版本 &#xff0c;我这台服务器是虚拟机,下面都是模拟实验 升级前一定要把服务器上配置文件&#xff0c;数据等进行备份 [rootlocalhost ~]#cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]#uname -a Linux jenkins_ser…

75.【C语言】文件操作(3)

目录 6.文件的顺序读写 1.几个顺序读写函数 1.fgetc函数 代码示例 代码改进 2.fputc函数 3.fputs函数 如果需要换行,应该写入换行符(\n) 4.fgets函数 1.读取单行字符串 2.读取多行字符串 6.文件的顺序读写 1.几个顺序读写函数 分组:(fgetc,fputc),(fgets,fputs),(f…

【数据结构-栈】【位运算优化】力扣3170. 删除星号以后字典序最小的字符串

给你一个字符串 s 。它可能包含任意数量的 ‘’ 字符。你的任务是删除所有的 ’ 字符。 当字符串还存在至少一个 ‘*’ 字符时&#xff0c;你可以执行以下操作&#xff1a; 删除最左边的 ‘’ 字符&#xff0c;同时删除该星号字符左边一个字典序 最小 的字符。如果有多个字典…

ENSP静态路由实验 10.11

0x01 拓扑图 0x02 配置各接口和PC1、2的IP地址 PC1&#xff1a; PC2&#xff1a; AR1&#xff1a; 配置AR1&#xff0c;改名为R1&#xff0c;并配置各接口IP&#xff0c;随后保存。 <R1>system-view [Huawei]sysname R1 [R1]int g0/0/2 [R1-GigabitEthernet0/0/2]ip ad…

Golang | Leetcode Golang题解之第456题132模式

题目&#xff1a; 题解&#xff1a; func find132pattern(nums []int) bool {candidateI, candidateJ : []int{-nums[0]}, []int{-nums[0]}for _, v : range nums[1:] {idxI : sort.SearchInts(candidateI, 1-v)idxJ : sort.SearchInts(candidateJ, -v)if idxI < idxJ {ret…

短剧小程序短剧APP在线追剧APP网剧推广分销微短剧小剧场小程序集师知识付费集师短剧小程序集师小剧场小程序集师在线追剧小程序源码

一、产品简介功能介绍 集师专属搭建您的独有短剧/追剧/小剧场小程序或APP平台 二、短剧软件私域运营解决方案 针对短剧类小程序的运营&#xff0c;以下提出10条具体的方案&#xff1a; 明确定位与目标用户&#xff1a; 对短剧类小程序进行明确定位&#xff0c;了解目标用户群体…

go发送邮件:在Go语言中实现发邮件的教程?

go发送邮件的教程指南&#xff1f;怎么使用Go语言发送电子邮件&#xff1f; Go语言&#xff0c;作为一种简洁、高效且并发性强的编程语言&#xff0c;自然也提供了丰富的库来支持邮件发送功能。AokSend将详细介绍如何在Go语言中实现发送邮件的功能&#xff0c;帮助你快速掌握这…

微信小程序和抖音小程序的分享和广告接入代码

开发完成小程序或者小游戏之后&#xff0c;我们为什么要接入分享和广告视频功能&#xff0c;主要原因有以下几个方面。 微信小程序和抖音小程序接入分享和广告功能主要基于以下几个原因&#xff1a; 用户获取与增长&#xff1a;分享功能可以帮助用户将小程序内容传播给更多人&…

垂直分库分表、水平分库分表

垂直分库&#xff1a;分出来的数据库的结构完全不一样&#xff0c;垂直分库&#xff0c;更像单体项目到问服务项目过度&#xff0c;根据业务拆分多个模块&#xff0c;每个模块把数据单独抽离出来作为数据库&#xff0c;垂直分库就是根据不同的表业务放在不同放数据库里&#xf…

小程序项目实践(一)--项目的初始化以及前期的准备工作

目录 1.起步 1.1 uni-app 简介 1.2 开发工具 1.2.1 下载 HBuilderX 1.2.2 安装 HBuilderX 1.2.3 安装 scss/sass 编译 1.2.4 快捷键方案切换 1.2.5 修改编辑器的基本设置 1.3 新建 uni-app 项目 1.4 目录结构 1.5 把项目运行到微信开发者工具 1.6 使用 Git 管理项目 …

ViT模型技术学习

前言 最近多模态模型特别火&#xff0c;模型也越来越小&#xff0c;MiniCPM-2.6只有8B&#xff0c;里面采用的图片编码器是SigLipViT模型&#xff0c;一起从头学习ViT和Transformer&#xff01;本文记录一下学习过程&#xff0c;所以是自上而下的写&#xff0c;从ViT拆到Trans…

cmd设置文件夹共享和清除磁盘的只读属性

背景&#xff1a;备份vm虚拟机到新上架的IBM交换机服务器 备份方法&#xff1a;设置服务器D:\盘为共享&#xff0c;再在其他机器通过IP地址共享路径访问服务器D:\盘&#xff0c;进行复制备份 交换机服务器操作系统&#xff1a;Microsoft hyper-v server 2016英文版&#xff0…

k3s安装指定版本以及离线安装(docker)

首先下载你所需要版本的k3s安装包&#xff0c;目录结构如下所示&#xff0c;我这里是v1.19.15k3s2。 1.首先赋予可执行权限后进行安装。 # k3s 需要赋予可执行权限 sudo chmod x k3s sudo chmod x k3s-install.sh2.然后将k3s的二进制文件复制到/usr/local/bin/ cp k3s /us…

【测试用例设计】一个登录界面的测试用例设计

文章目录 1. 登录页面的测试用例设计 1. 登录页面的测试用例设计

2024 好玩有趣的nc(netcat)瑞士军刀,可以玩的对话工具哦!超级简单,包会,图文讲解,不讲虚话

一、nc是什么&#xff1f; 在Linux系统中&#xff0c;nc&#xff08;即netcat&#xff09;是一个非常强大的网络工具&#xff0c;常被昵称为“瑞士军刀”。它能够通过TCP或UDP协议读写网络连接&#xff0c;被广泛应用于网络调试和检测。 二、nc具体怎么进行通讯呢&#xff1f;&…

通信工程学习:什么是RIP路由信息协议

RIP&#xff1a;路由信息协议 RIP&#xff08;Routing Information Protocol&#xff09;路由信息协议是一种基于距离矢量算法的内部网关协议&#xff08;IGP&#xff09;&#xff0c;主要用于在自治系统&#xff08;AS&#xff09;内部进行路由信息的交换和传播。以下是关于RI…

【机器学习】随机森林算法(看我以弱博强)

目录 算法引入&#xff1a; 算法介绍&#xff1a; 1. 集成学习&#xff1a; 2. 训练过程&#xff1a; 3. 分类和回归&#xff1a; 算法优点&#xff1a; 算法缺点&#xff1a; 算法实现&#xff1a; 1. 数据准备 2. 划分数据集 3. 创建随机森林模型 4. 训练模型 5…