VUE+vue-drag-resize实现点位添加拖拽

这个组件是VUE+vue-drag-resize +canvas 实现的点位添加拖拽,下面是整体效果:

在这里插入图片描述

首先有一个上传页面上传背景
在这里插入图片描述

代码如下:

	<!-- 上传组件 -->
   <el-upload class="upload-demo" drag action="https://jsonplaceholder.typicode.com/posts/" multiple
        v-show="isUpload" :on-success="uploadSuccess" :on-error="uploadError">
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
   </el-upload>

图片上传成功后显示canvas画布

HTML代码如下:

<!-- 生成画布模块 -->
      <div class="canvas-box" v-show="this.canvasinit && !isUpload">

        <!-- 画布 -->
        <canvas ref="canvas" :width="canvasWidth" :height="canvasHeight" @mousedown="canvasMouseDown" @mouseup="canvasMouseUp"></canvas>
        <!-- 点位 -->
        <vue-drag-resize v-for="(item,index) in canvasSensorImg" :isActive="true" :isResizable="false" :parentLimitation="true"
          :isDraggable="!isDelete && !isEditor" :parentW="parent.w" :parentH="parent.h" @dragstop="dragstop" :x="item.x"
          :y="item.y" :z="999" :w="item.width" :h="item.height" class="drag2">
          <!-- <img :src="item.url" alt="" srcset=""> -->
          <div class="text"> V{{ index + 1 }}</div>
         

          <img src="../../../../public/img/disposition/delete.png" alt="" srcset="" class="delete" @click="goDelete"
            v-show="isDelete">
          <img src="../../../../public/img/disposition/editor.png" alt="" srcset="" class="editor" @click="goEditor"
            v-show="isEditor">

        </vue-drag-resize>
        <!-- 卡片 -->
        <vue-drag-resize v-for="item in tagList" :isActive="true" :isResizable="false" :parentLimitation="true"
          :isDraggable="!isDelete && !isEditor" :parentW="parent.w" :parentH="parent.h" @dragstop="dragstop" :x="item.x"
          :y="item.y" :z="999" :w="200" :h="80" class="drag">
          <img src="../../../../public/img/disposition/shui.png" alt="" srcset="">
          <ul>
            <li>{{item.name}}</li>
            <li>{{item.temperature}}<span></span></li>
          </ul>

          <img src="../../../../public/img/disposition/delete.png" alt="" srcset="" class="delete" @click="goDelete"
            v-show="isDelete">
          <img src="../../../../public/img/disposition/editor.png" alt="" srcset="" class="editor" @click="goEditor"
            v-show="isEditor">
        </vue-drag-resize>


      </div>
// 创建画布
      init() {
        // 找到画布标签
        this.canvas = this.$refs.canvas;
        this.ctx = this.canvas.getContext("2d");
        console.log('创建画布')
        // 创建背景,图标,移动图标
        this.loadBgImg();
        // 刷新画布
      },
      loadBgImg() {
        let img = new Image();
        let bgImg = this.backgroundImg;
        img.src = bgImg.url;
        img.onload = () => {
          this.canvasWidth = img.width;
          this.canvasHeight = img.height;
          this.ctx.clearRect(0, 0, img.width, img.height);
          this.ctx.drawImage(img, bgImg.x, bgImg.y, img.width, img.height);
          this.parent.w = img.width
          this.parent.h = img.height

          document.querySelector('.canvas-box').style.width = img.width + 'px';
          document.querySelector('.canvas-box').style.height = img.height + 'px';

        };
      },

在这里插入图片描述

完整代码如下

<template>
  <div element-loading-spinner="el-icon-loading" element-loading-text="加载中"
         v-loading="itemLoading">
  <div style="margin-left: -5px">
    <tree-breadcrumb :list="treeList" @onClickItem="onClickItem"></tree-breadcrumb>
  </div>
  <el-select v-model="value" placeholder="请选择" class="equipmentSelect">
    <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value">
    </el-option>
  </el-select>
  <div class="FeatureList" v-show="!isUpload">
    <el-button type="primary" plain size="mini" @click="Editor">{{isEditor?'取消编辑':'编辑'}}</el-button>
    <el-button type="primary" plain size="mini" @click="updateBackground" v-show="isEditor">更新底图</el-button>

    <el-button type="danger" plain size="mini" @click="Delete">{{isDelete?'取消删除':'删除'}}</el-button>
    <el-button type="danger" plain size="mini" @click="deleteBackground" v-show="isDelete">删除底图</el-button>


  </div>
  <div class="app-container">
    
    <div class="clear"></div>

    <div class="grid-right">

      <!-- 上传组件 -->
      <el-upload class="upload-demo" drag action="https://jsonplaceholder.typicode.com/posts/" multiple
        v-show="isUpload" :on-success="uploadSuccess" :on-error="uploadError">
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
      </el-upload>



      <!-- 生成画布模块 -->
      <div class="canvas-box" v-show="this.canvasinit && !isUpload">

        <!-- 画布 -->
        <canvas ref="canvas" :width="canvasWidth" :height="canvasHeight" @mousedown="canvasMouseDown" @mouseup="canvasMouseUp"></canvas>
        <!-- 点位 -->
        <vue-drag-resize v-for="(item,index) in canvasSensorImg" :isActive="true" :isResizable="false" :parentLimitation="true"
          :isDraggable="!isDelete && !isEditor" :parentW="parent.w" :parentH="parent.h" @dragstop="dragstop" :x="item.x"
          :y="item.y" :z="999" :w="item.width" :h="item.height" class="drag2">
          <!-- <img :src="item.url" alt="" srcset=""> -->
          <div class="text"> V{{ index + 1 }}</div>
         

          <img src="../../../../public/img/disposition/delete.png" alt="" srcset="" class="delete" @click="goDelete"
            v-show="isDelete">
          <img src="../../../../public/img/disposition/editor.png" alt="" srcset="" class="editor" @click="goEditor"
            v-show="isEditor">

        </vue-drag-resize>
        <!-- 卡片 -->
        <vue-drag-resize v-for="item in tagList" :isActive="true" :isResizable="false" :parentLimitation="true"
          :isDraggable="!isDelete && !isEditor" :parentW="parent.w" :parentH="parent.h" @dragstop="dragstop" :x="item.x"
          :y="item.y" :z="999" :w="200" :h="80" class="drag">
          <img src="../../../../public/img/disposition/shui.png" alt="" srcset="">
          <ul>
            <li>{{item.name}}</li>
            <li>{{item.temperature}}<span></span></li>
          </ul>

          <img src="../../../../public/img/disposition/delete.png" alt="" srcset="" class="delete" @click="goDelete"
            v-show="isDelete">
          <img src="../../../../public/img/disposition/editor.png" alt="" srcset="" class="editor" @click="goEditor"
            v-show="isEditor">
        </vue-drag-resize>


      </div>
    </div>

    <!-- 添加监测点弹窗 -->
    <el-dialog :title="dialogFormTitle" :visible.sync="dialogFormVisible" :modal-append-to-body='false'>
      <el-form :model="form">

        <el-form-item label="监测点" :label-width="formLabelWidth">
          <el-select v-model="form.region1" placeholder="请选择监测点">
            <el-option label="选项1" value="1"></el-option>
            <el-option label="选项2" value="2"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="监测项" :label-width="formLabelWidth">
          <el-select v-model="form.region2" placeholder="请选择监测项">
            <el-option label="选项1" value="1"></el-option>
            <el-option label="选项2" value="2"></el-option>
          </el-select>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogFormVisible = false">取 消</el-button>
        <el-button type="primary" @click="save">确 定</el-button>
      </div>
    </el-dialog>

    <!-- 更新背景 -->
    <el-dialog title="更新背景" :visible.sync="isUpdateBackground" :modal-append-to-body='false'>
      <el-upload class="upload-demo" drag action="https://jsonplaceholder.typicode.com/posts/" multiple>
        <i class="el-icon-upload"></i>
        <div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
        <div class="el-upload__tip" slot="tip">只能上传jpg/png文件,且不超过500kb</div>
      </el-upload>
      <div slot="footer" class="dialog-footer">
        <el-button @click="isUpdateBackground = false">取 消</el-button>
        <el-button type="primary" @click="isUpdateBackground = false">确 定</el-button>
      </div>
    </el-dialog>




  </div>
  </div>
</template>

<script>
  import VueDragResize from 'vue-drag-resize';
  import TreeBreadcrumb from '../../../components/tree-breadcrumb/main'
  import Cookies from 'js-cookie'
  const imgUrl = require('../../../../public/img/disposition/backgroundImg.png')

  export default {
    name: "ce_shi",
    components: {
      VueDragResize,
      TreeBreadcrumb
    },
    props: {
      deptList: {
        type: Array,
        default: []
      }
    },
    watch: {
      deptList: function (val) {
        //刷新数据
        this.treeList = val;
        this.deptId = val[val.length - 1].id;
    
        //调用刷新页面数据方法
        // this.onLoad(this.page);
      },
    },
    data() {
      return {
        treeList: [],
        deptId:'',
        options: [{
          value: '1',
          label: '减速机-01'
        }, {
          value: '2',
          label: '减速机-02'
        }, {
          value: '3',
          label: '减速机-03'
        }],
        value: '1',
        // x显示标签添加弹窗
        dialogFormVisible: false,
        dialogFormTitle: '',
        formLabelWidth: '120px',
        isEditor: false,//是否开启编辑模式
        isDelete: false,//是否开启删除模式
        isUpload: true,
        isUpdateBackground:false,//更新背景弹窗
        form: {
          region1: '',
          region2: '',

        },
        parent: {
          w: 1920,
          h: 1080
        },
        //鼠标点击创建数据
        pointData: {},
        // 获取canvas标签
        canvas: null,
        // 创建画布
        ctx: null,
        // 画布大小
        canvasWidth: 970,
        canvasHeight: 500,
        //定时器
        intervalId: null,
        //判断鼠标是否点击
        isClick: false,
        //记录需要移动的图片的开光
        index: -1,
        frameNumber: 20,
        // 标签卡片数组
        tagList: [{
          x: 20,
          y: 50,
          name: 'OT-润滑油油温',
          temperature: '46℃'
        }],

        backgroundImg: {
          // url: "https://img2.baidu.com/it/u=2832413337,2216208892&fm=253&fmt=auto&app=138&f=JPEG?w=544&h=500",
          url: imgUrl,
          x: 0,
          y: 0,
          width: 970,
          height: 500,
        },
        canvasSensorImg: [
          {
            channelId: 12,
            height: 26,
            url: "https://img2.baidu.com/it/u=3823882177,3352315913&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
            width: 26,
            x: 247,
            y: 233,
          }
        ],

        // 图标数据
        Icondata:
          "https://img2.baidu.com/it/u=3823882177,3352315913&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",

        // 画布开关
        canvasinit: false,
        itemLoading:true




      };
    },
    created() {

    },
    mounted() {
      if (Cookies.get('breadcrumb')) {
        this.refreshItem();
      } else {
        this.itemLoading = true;
        var timer = setInterval(() => {
          if (Cookies.get('breadcrumb')) {
            this.itemLoading = false;
            clearInterval(timer);
            this.refreshItem();
          }
        }, 2000)
      }
      this.canvasinit = true;
      this.init();
      this.itemLoading = false
    },
    methods: {
      // 顶部面包屑
      refreshItem() {
        let list = JSON.parse(Cookies.get('breadcrumb'));
        this.treeList = list;
        this.deptId = list[list.length - 1].id;
       
      },
      onClickItem(id, label, index) {
        this.treeList.splice(index + 1);
        let data = {
          list: this.treeList,
          flag: 0
        };
        this.$emit("changeCrumbs", data);
      },
      // 更新背景
      updateBackground() {
        this.isUpdateBackground = true
      },
      deleteBackground(){
        this.goDelete()
      },
     
      // 上传成功
      uploadSuccess(e) {
      
        this.isUpload = false
      },
      // 上传失败
      uploadError() {
       
        this.isUpload = false
      },
      // 拖动结束
      dragstop(e) {

        console.log(e)
      },
      // 开启/关闭编辑模式
      Editor() {
        this.isDelete = false
        this.isEditor = !this.isEditor
       

      },
      // 开启/关闭删除模式 
      Delete() {
        this.isEditor = false
        this.isDelete = !this.isDelete


      },
      goDelete() {
        this.$confirm('此操作将永久删除该文件, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          this.$message({
            type: 'success',
            message: '删除成功!'
          });
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消删除'
          });
        });


      },
      goEditor() {
        this.dialogFormVisible = true
        this.dialogFormTitle = '显示标签编辑'

      },

      // 定时器刷新画布
      dataRefreh() {
        if (this.intervalId != null) {
          return;
        }
        this.intervalId = setInterval(() => {
          this.loadBgImg();
        }, this.frameNumber);
      },

      // 创建画布
      init() {
        // 找到画布标签
        this.canvas = this.$refs.canvas;
        this.ctx = this.canvas.getContext("2d");
        console.log('创建画布')
        // 创建背景,图标,移动图标
        this.loadBgImg();
        // 刷新画布
        this.dataRefreh();
      },
      loadBgImg() {
        let img = new Image();
        let bgImg = this.backgroundImg;
        img.src = bgImg.url;
        img.onload = () => {
          this.canvasWidth = img.width;
          this.canvasHeight = img.height;
          this.ctx.clearRect(0, 0, img.width, img.height);
          this.ctx.drawImage(img, bgImg.x, bgImg.y, img.width, img.height);
          this.parent.w = img.width
          this.parent.h = img.height

          document.querySelector('.canvas-box').style.width = img.width + 'px';
          document.querySelector('.canvas-box').style.height = img.height + 'px';

        };
      },

      //判断鼠标是否在图标范围内,并返回下标
      isMouseInIcon(e, imgList) {
        let x = e.offsetX;
        let y = e.offsetY;
        for (let i = 0; i < imgList.length; i++) {
          let imgX = imgList[i].x;
          let imgY = imgList[i].y;
          let imgWidth = imgList[i].width;
          let imgHeight = imgList[i].height;
          if (
            x > imgX &&
            x < imgX + imgWidth &&
            y > imgY &&
            y < imgY + imgHeight
          ) {
            return i;
          }
        }
        return -1;
      },

      //鼠标点击触发事件
      canvasMouseDown(e) {

        // 获取鼠标位置
        const { clientX, clientY } = event;
        // 获取canvas 边界位置
        const { top, left } = this.canvas.getBoundingClientRect();
        // 计算鼠标在canvas 中的位置
        const x = clientX - left;
        const y = clientY - top;
        // 之前选过值的
        var data = {
          x: x,
          y: y
        }
        console.log("鼠标点击", e);
        this.isClick = true;
        this.showdialogVisible(data)
        this.pointData = data

      },

      //鼠标抬起触发事件
      canvasMouseUp(e) {
  
        this.isClick = false;
      },
      handleClick(data) {
        // 判断是否上传楼层图片
        // 创建点位
        let imgs = {};
        imgs.url = this.Icondata;
        imgs.x = data.x;
        imgs.y = data.y;
        imgs.width = 26;
        imgs.height = 26;
        // 加载点位图标
        this.canvasSensorImg.push(imgs);
        this.$message.success("创建成功");

        let item = {}
        item.x = data.x - 50
        item.y = data.y - 80
        item.name = 'OT-润滑油油温'
        item.temperature = '46℃'


        this.tagList.push(item);
      },
      showdialogVisible(data) {
        if (this.isDelete || this.isEditor) {
          return
        }
        this.dialogFormTitle = '显示标签添加'
        this.dialogFormVisible = true
      },
      save() {
        this.handleClick(this.pointData)
        this.dialogFormVisible = false
      }
    },
    beforeDestroy() {
      clearInterval(this.intervalId);
      this.intervalId = null;
    },
  };
</script>
<style lang="scss" scoped>
  .app-container {
    background: #fff;
    width: 100%;
    height: 100%;
    position: relative;
    /* float: left; */
    overflow: scroll;
    /* overflow: hidden; */
  }

  .item {
    width: 100px;
    height: 100px;
    background: red;
  }

  .drag2 img {
    width: 100%;
    height: 100%;
    cursor: pointer;
  }

  .drag {
    background: url(../../../../public/img/disposition/bg.png) no-repeat;
    background-size: 100% 100%;
    cursor: pointer;
  }

  .drag.active:before,
  .drag2.active:before {
    outline: none;
  }

  .drag img {
    width: 40px;
    float: left;
    margin-top: 10px;
    margin-left: 20px;
  }

  ul {
    width: 140px;
    display: inline-block;
    float: left;
    margin: 0;
    padding: 10px 10px 0 0;
    box-sizing: border-box;

  }

  ul li {
    list-style: none;
    text-align: right;
    font-weight: bold;
    font-size: 14px;
    margin-bottom: 5px;
  }

  ul li span {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 5px;
    background-color: green;
    margin-left: 5px;
  }

  .canvas-box {
    margin: 0 auto;
    position: relative;
  }

  .equipmentSelect {
 
    position: absolute;
    top: 60px;
    right: 30px;
    z-index: 1000;

  }

  .FeatureList {
    padding: 0 20px;

    float: left;
    position: absolute;
    top: 60px;
    left: 20px;
    z-index: 1000;
  }

  .drag2 img.delete,
  .drag img.delete {
    width: 30px;
    height: 30px;
    position: absolute;
    top: -15px;
    right: -15px;
    z-index: 9999;
  }
  .drag img.delete{
    top: -25px;
  }
  

  .drag2 img.editor,
  .drag img.editor {
    width: 18px;
    height: 18px;
    position: absolute;
    top: -9px;
    right: -8px;
    z-index: 9999;
  }

  .upload-demo {
    display: block;
    width: 500px;
    margin: 100px auto 100px;
  }

  .clear {
    width: 100%;
    clear: both;
  }
  .text{
    width: 100%;
    height: 100%;
    text-align: center;
    line-height: 26px;
    color: #1479e1;
    font-weight: bold;
    font-size: 16px;
    cursor: pointer;
  }
</style>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱蹦跶的大A阿

你的打赏就是我蹦跶的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值