欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

vue使用canvas畫布實現(xiàn)平面圖點位標注功能(最新推薦)

 更新時間:2023年07月28日 15:13:56   作者:-風(fēng)過無痕  
這篇文章主要介紹了vue使用canvas畫布實現(xiàn)平面圖點位標注功能,經(jīng)過本文一番研究發(fā)現(xiàn)canvas標簽可以完成很多功能,電子簽名,點位標注,問題標注,畫圖功能,感興趣的朋友跟隨小編一起看看吧

前言

  • 最近需要一個在平面圖標注點位功能,去搜了一圈,發(fā)現(xiàn)......,最后在查閱文檔一頓操作之后。
  • 不停修改bug之后,做出一版可以基本使用的版本。
  • 最后發(fā)現(xiàn)canvas標簽可以完成很多功能,電子簽名,點位標注,問題標注,畫圖功能等等

效果

功能難點

畫布渲染問題-基于canvas提供的渲染方法封裝渲染方法,x,y坐標,width,height高,url圖片

移動距離問題-我們需要借助鼠標點擊,移動,彈起來事件計算移動的距離,來更改x,y坐標

選中圖標問題-當(dāng)我們畫布上有多個圖標時通過x,y,加上width,height和點擊時x,y坐標判斷是那個圖標在被點擊,在數(shù)組中找到匹配返回下標,反之就是點擊背景圖

畫布渲染問題-生成畫布之后,為了讓用戶無感操作,最好以幀方式刷新畫布(定時器方式)

圖標數(shù)據(jù)格式-畫布上圖標有很多個圖標,改變一個同時,其他也是要跟著渲染

設(shè)備信息問題-我們需要在畫布上點擊獲取到圖標的下標之后,把x,y傳遞給信息框,顯示

自己理解

現(xiàn)在這個版本僅僅相當(dāng)于是一個例子,但是也是費了不少時間和bug才艱辛完成的

為什么說是例子,可能還會有bug,適配,api交互,放大,存儲問題等等。

代碼實現(xiàn)-可以直接復(fù)制

<template>
  <div class="app-container">
    <!-- 側(cè)邊欄 -->
    <el-row :gutter="20">
      <!-- 樹結(jié)構(gòu) -->
      <el-col :xs="24" :sm="4" :lg="4">
        <div class="grid-left">
          <!-- 篩選框 -->
          <el-input
            class="searchinput"
            placeholder="請搜索樓層"
            suffix-icon="el-input__icon el-icon-search"
            v-model="treeinput"
            clearable
            size="small"
          ></el-input>
          <!-- 樹結(jié)構(gòu) -->
          <el-tree
            :data="treedata"
            :props="defaultProps"
            @node-click="handleNodeClick"
            ref="menuTree"
            node-key="id"
            default-expand-all
            :filter-node-method="filterNode"
          ></el-tree>
        </div>
      </el-col>
      <!-- 點位模塊 -->
      <el-col :xs="24" :sm="15" :lg="15">
        <div class="grid-right">
          <!-- 點位標題 -->
          <div class="grid-top"></div>
          <!-- 圖片展示 -->
          <img class="bigImg" :src="backpicture" v-if="backpicture" />
          <!-- 生成畫布模塊 -->
          <div class="canvas-box" v-show="this.canvasinit">
            <!-- 表頭 -->
            <div class="canvas-title">
              <div class="zuo">
                請拖動圖標到安裝位置-<i>廠家平面圖 平面圖</i>
              </div>
            </div>
            <!-- 畫布 -->
            <canvas
              ref="canvas"
              width="970"
              height="500"
              @mousedown="canvasMouseDown"
              @mousemove="canvasMouseMove"
              @mouseup="canvasMouseUp"
            ></canvas>
          </div>
          <!-- 保存平面圖 -->
          <div class="bottom" v-if="!this.canvasinit">
            <el-button type="primary" @click="save">保存</el-button>
          </div>
          <!-- 圖標提示信息 -->
          <el-popover
            placement="top"
            id="popovercan"
            width="200"
            v-model="canvasvisible"
          >
            <div class="popover-top">
              <i>傳感器設(shè)備</i>
            </div>
            <p>序列號:sjhdkjshkj</p>
            <p>設(shè)備類型:是給大家灰色軌跡</p>
            <p></p>
          </el-popover>
        </div>
      </el-col>
      <!-- 設(shè)備信息 -->
      <el-col :xs="24" :sm="5" :lg="5">
        <div class="grid-table">
          <!-- 標題 -->
          <div class="grid-top">
            <i></i>
            <p>配置資源點-點擊圖標加載到畫布中</p>
          </div>
          <!-- 表格數(shù)據(jù) -->
          <div class="newtable">
            <div
              class="new-item"
              v-for="item in tableData"
              :key="item.id"
              @click="handleClick(item)"
            >
              <img :src="item.img" alt="" />
              <div class="newconter">
                <p>序列號碼:{{ item.phone }}</p>
                <p>設(shè)備類型:{{ item.newtype }}</p>
                <p>詳細位置:{{ item.sys }}</p>
              </div>
            </div>
          </div>
          <div class="pagination">
            <el-pagination
              small
              :page-size="pageInfo.pageSize"
              layout="prev, pager, next"
              :total="pageInfo.total"
            >
            </el-pagination>
          </div>
        </div>
      </el-col>
    </el-row>
  </div>
</template>
?
<script>
export default {
  name: "Ceshi",
  watch: {
    treeinput(val) {
      this.$refs.menuTree.filter(val);
    },
  },
  data() {
    return {
      // 樹結(jié)構(gòu)篩選框
      treeinput: "",
      // 樹結(jié)構(gòu)數(shù)據(jù)
      treedata: [
        {
          id: 1,
          name: "中國",
          children: [
            {
              id: 1,
              name: "廣東",
              children: [
                {
                  id: 4,
                  name: "惠州",
                },
                {
                  id: 5,
                  name: "深圳",
                },
                {
                  id: 6,
                  name: "廣州",
                },
              ],
            },
            {
              id: 2,
              name: "湖北",
              children: [
                {
                  id: 7,
                  name: "武漢",
                },
              ],
            },
            {
              id: 3,
              name: "北京",
            },
          ],
        },
      ],
      // 樹結(jié)構(gòu)配置
      // 樹形數(shù)據(jù)分析
      defaultProps: {
        id: "id",
        label: "name",
        children: "children",
      },
      // 獲取canvas標簽
      canvas: null,
      // 創(chuàng)建畫布
      ctx: null,
      // 畫布大小
      canvasWidth: 970,
      canvasHeight: 500,
      //定時器
      intervalId: null,
      //判斷鼠標是否點擊
      isClick: false,
      //記錄需要移動的圖片的開光
      index: -1,
      frameNumber: 20,
      sensorImgList: [],
      backgroundImg: {
        url: "https://img2.baidu.com/it/u=2832413337,2216208892&fm=253&fmt=auto&app=138&f=JPEG?w=544&h=500",
        x: 0,
        y: 0,
        width: 970,
        height: 500,
      },
      canvasSensorImg: [
        {
          channelId: 12,
          height: 46,
          url: "https://img2.baidu.com/it/u=3823882177,3352315913&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          width: 46,
          x: 247,
          y: 233,
        },
        {
          channelId: 13,
          height: 46,
          url: "https://img2.baidu.com/it/u=3823882177,3352315913&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          width: 46,
          x: 400,
          y: 400,
        },
      ],
      tableData: [
        {
          id: 1,
          img: "https://img2.baidu.com/it/u=3823882177,3352315913&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
          phone: "865566043823044",
          newtype: "NP-FDY100-N",
          sys: "中國北京市北京人名大會堂側(cè)門旁邊",
        },
      ],
      // 圖標數(shù)據(jù)
      Icondata:
        "https://img2.baidu.com/it/u=3823882177,3352315913&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500",
      // 背景圖圖片
      backpicture:
        "https://img2.baidu.com/it/u=2832413337,2216208892&fm=253&fmt=auto&app=138&f=JPEG?w=544&h=500",
      // 畫布開關(guān)
      canvasinit: false,
      // 設(shè)備抱緊查詢
      pageInfo: {
        // 總條數(shù)
        total: 17,
        // 當(dāng)前頁
        pageNo: 1,
        // 每頁條數(shù)
        pageSize: 10,
      },
      clickicon: {},
      canvasvisible: false,
    };
  },
  created() {},
  methods: {
    // 樹結(jié)構(gòu)點擊事件
    handleNodeClick(data) {
      if (data.children.length !== 0) {
        return;
      }
      console.log("樹形結(jié)構(gòu)", data);
      console.log(data.id);
      // 樓層id
      this.page.floorId = data.id;
    },
    // 樹節(jié)點搜索
    filterNode(value, data) {
      if (!value) return true;
      return data.name.indexOf(value) !== -1;
    },
    // 確認保存按鈕
    save() {
      this.canvasinit = true;
      this.init();
    },
    // 創(chuàng)建畫布
    init() {
      // 找到畫布標簽
      this.canvas = this.$refs.canvas;
      this.ctx = this.canvas.getContext("2d");
      // 創(chuàng)建背景,圖標,移動圖標
      this.loadBgImg();
      // 刷新畫布
      this.dataRefreh();
    },
    loadBgImg() {
      let img = new Image();
      let bgImg = this.backgroundImg;
      img.src = bgImg.url;
      img.onload = () => {
        this.ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight);
        this.ctx.drawImage(img, bgImg.x, bgImg.y, bgImg.width, bgImg.height);
        this.drawCanvasSensorImg();
        this.loadSensorImg();
      };
    },
    //加載圖標
    loadSensorImg() {
      let imgList = [];
      for (let i = 0; i < this.sensorImgList.length; i++) {
        let img = new Image();
        let sensorImg = this.sensorImgList[i];
        img.src = sensorImg.url;
        let imgs = {};
        imgs.img = img;
        imgs.x = sensorImg.x;
        imgs.y = sensorImg.y;
        imgs.width = sensorImg.width;
        imgs.height = sensorImg.height;
        // console.log(imgs)
        imgList.push(imgs);
      }
      this.drawImg(imgList);
    },
    //繪制圖片方法
    drawImg(imgList) {
      for (let i = 0; i < imgList.length; i++) {
        this.ctx.drawImage(
          imgList[i].img,
          imgList[i].x,
          imgList[i].y,
          imgList[i].width,
          imgList[i].height
        );
      }
    },
    // 繪制移動的圖片
    drawCanvasSensorImg() {
      let imgList = [];
      for (let i = 0; i < this.canvasSensorImg.length; i++) {
        let img = new Image();
        let sensorImg = this.canvasSensorImg[i];
        img.src = sensorImg.url;
        let imgs = {};
        imgs.img = img;
        imgs.x = sensorImg.x;
        imgs.y = sensorImg.y;
        imgs.width = sensorImg.width;
        imgs.height = sensorImg.height;
        imgList.push(imgs);
      }
      this.drawImg(imgList);
    },
    //判斷鼠標是否在圖標范圍內(nèi),并返回下標
    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;
    },
    // 定時器刷新畫布
    dataRefreh() {
      if (this.intervalId != null) {
        return;
      }
      this.intervalId = setInterval(() => {
        this.loadBgImg();
      }, this.frameNumber);
    },
    //鼠標點擊觸發(fā)事件
    canvasMouseDown(e) {
      console.log("鼠標點擊", e);
      this.isClick = true;
      this.index = this.isMouseInIcon(e, this.canvasSensorImg);
?
      if (this.index == -1) {
        console.log("沒選中");
        return;
      }
      this.$nextTick(() => {
        console.log("top");
        const canpro = document.getElementById("popovercan");
        canpro.style.position = "absolute";
        canpro.style.top = this.canvasSensorImg[this.index].y + 40 + "px";
        canpro.style.left = this.canvasSensorImg[this.index].x - 60 + "px";
        this.canvasvisible = !this.canvasvisible;
      });
    },
    //鼠標移動觸發(fā)事件
    canvasMouseMove(e) {
      if (!this.isClick) {
        return;
      }
      if (this.index != -1) {
        this.canvasvisible = false;
        let x = e.offsetX;
        let y = e.offsetY;
        this.canvasSensorImg[this.index].x =
          this.canvasSensorImg[this.index].x < 0
            ? 0
            : x - this.canvasSensorImg[this.index].width / 2;
        this.canvasSensorImg[this.index].y =
          this.canvasSensorImg[this.index].y < 0
            ? 0
            : y - this.canvasSensorImg[this.index].height / 2;
      }
    },
    //鼠標抬起觸發(fā)事件
    canvasMouseUp(e) {
      console.log("執(zhí)行了");
      this.isClick = false;
    },
    handleClick(item) {
      // 判斷是否上傳樓層圖片
        // 創(chuàng)建點位
        let imgs = {};
        imgs.url = this.Icondata;
        imgs.x = 0;
        imgs.y = 0;
        imgs.width = 46;
        imgs.height = 46;
        // 加載點位圖標
        this.canvasSensorImg.push(imgs);
        this.$message.success("請拖動圖標到指定點位");
    },
  },
  beforeDestroy() {
    clearInterval(this.intervalId);
    this.intervalId = null; 
  },
};
</script>
?
<style lang="scss" scoped>
.app-container {
  height: 815px;
  .grid-left {
    padding: 30px 20px 20px;
    min-height: 815px;
    border: 1px solid #ccc;
    // 輸入框
    .searchinput {
      margin-bottom: 20px;
    }
  }
  .grid-right {
    // width: 1363px;
    width: 100%;
    height: 815px;
    padding: 30px 20px 20px;
    border: 1px solid #ccc;
    position: relative;
    // 標題
    .grid-top {
      width: 100%;
    }
    // 圖片展示
    .bigImg {
      display: block;
      width: 970px;
      height: 500px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -54%);
    }
    // 畫布模塊
    .canvas-box {
      width: 1000px;
      height: 620px;
      padding: 10px;
      background-color: #fff;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -55%);
      cursor: pointer;
      .canvas-title {
        display: flex;
        // background-color: skyblue;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 10px;
      }
    }
    // 保存平面圖
    .bottom {
      width: 95%;
      height: 100px;
      border-top: 1px solid #ccc;
      display: flex;
      justify-content: center;
      align-items: center;
      // background-color: skyblue;
      position: absolute;
      left: 50%;
      transform: translateX(-50%);
      bottom: 0;
    }
    // 設(shè)備彈出框
    ::v-deep .el-popover {
      // background-color: skyblue;
      padding: 0;
      .popover-top {
        display: flex;
        justify-content: space-between;
        align-items: center;
        .popover-title {
          width: 30px;
          height: 35px;
          cursor: pointer;
          background-color: #e72528;
          display: flex;
          justify-content: center;
          align-items: center;
          border-radius: 0 5px 0 0;
          i {
            font-size: 25px;
          }
        }
        i {
          font-style: normal;
          // font-size: 20px;
        }
      }
      p {
        margin: 3px 0;
      }
    }
  }
  .grid-table {
    padding: 30px 5px 5px;
    height: 815px;
    border: 1px solid #ccc;
    .grid-top {
      display: flex;
      align-items: center;
      // background-color: skyblue;
      i {
        display: block;
        width: 3px;
        height: 19px;
        background-color: #409eff;
        // border-radius: 2px;
        margin-right: 5px;
      }
      p {
        // font-size: 17px;
        // font-weight: 700;
        color: rgb(36, 37, 37);
      }
    }
    // 設(shè)備列表
    .newtable {
      background-color: #fff;
      .new-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        height: 80px;
        padding: 0 5px;
        cursor: pointer;
        // background-color: skyblue;
        border-top: 2px solid #c8c8c8;
        // border-bottom: 2px solid #c8c8c8;
        &:last-child {
          border-bottom: 2px solid #c8c8c8;
        }
        img {
          width: 45px;
          height: 45px;
        }
        .newconter {
          margin-left: 10px;
          font-size: 12px;
          p {
            padding: 0;
            margin: 2px 0;
          }
        }
      }
    }
    .pagination {
      margin-top: 10px;
      display: flex;
      justify-content: center;
      align-content: center;
    }
  }
}
</style>

總結(jié):

經(jīng)過這一趟流程下來相信你也對 vue-使用canvas畫布實現(xiàn)平面圖點位標注功能 有了初步的深刻印象,但在實際開發(fā)中我 們遇到的情況肯定是不一樣的,所以我們要理解它的原理,萬變不離其宗。

到此這篇關(guān)于vue使用canvas畫布實現(xiàn)平面圖點位標注功能的文章就介紹到這了,更多相關(guān)vue canvas平面圖點位標注內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 前端vue+element使用SM4國密加密解密的詳細實例

    前端vue+element使用SM4國密加密解密的詳細實例

    國密即國家密碼局認定的國產(chǎn)密碼算法,主要有SM1,SM2,SM3,SM4,下面這篇文章主要給大家介紹了關(guān)于前端vue+element使用SM4國密加密解密的相關(guān)資料,需要的朋友可以參考下
    2023-03-03
  • vue.js body的css不生效問題及解決

    vue.js body的css不生效問題及解決

    這篇文章主要介紹了vue.js body的css不生效問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-06-06
  • 在IDEA中配置eslint和prettier的全過程

    在IDEA中配置eslint和prettier的全過程

    日常開發(fā)中,建議用可以用Prettier做代碼格式化,然后用eslint做校驗,下面這篇文章主要給大家介紹了關(guān)于在IDEA中配置eslint和prettier的相關(guān)資料,需要的朋友可以參考下
    2024-02-02
  • vue實現(xiàn)百度搜索功能

    vue實現(xiàn)百度搜索功能

    這篇文章主要為大家詳細介紹了vue實現(xiàn)百度搜索功能,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-09-09
  • vue3利用store實現(xiàn)記錄滾動位置的示例

    vue3利用store實現(xiàn)記錄滾動位置的示例

    這篇文章主要介紹了vue3利用store實現(xiàn)記錄滾動位置的示例,幫助大家更好的理解和學(xué)習(xí)使用vue框架,感興趣的朋友可以了解下
    2021-04-04
  • @vue/cli4升級@vue/cli5?node.js?polyfills錯誤的解決方式

    @vue/cli4升級@vue/cli5?node.js?polyfills錯誤的解決方式

    最近在升級vue/cli的具有了一些問題,解決問題的過程也花費了些時間,所以下面這篇文章主要給大家介紹了關(guān)于@vue/cli4升級@vue/cli5?node.js?polyfills錯誤的解決方式,需要的朋友可以參考下
    2022-09-09
  • Vue實現(xiàn)表格數(shù)據(jù)的增刪改查的示例代碼

    Vue實現(xiàn)表格數(shù)據(jù)的增刪改查的示例代碼

    Vue是一個用于構(gòu)建用戶界面的JavaScript框架,在Vue中可以通過使用Vue組件來實現(xiàn)對表格的增刪改查操作,下面將介紹一些基礎(chǔ)的Vue組件和技術(shù)來實現(xiàn)對表格的增刪改查操作,需要的朋友可以參考下
    2024-08-08
  • elementui 開始結(jié)束時間可以選擇同一天不同時間段的實現(xiàn)代碼

    elementui 開始結(jié)束時間可以選擇同一天不同時間段的實現(xiàn)代碼

    這篇文章主要介紹了elementui 開始結(jié)束時間可以選擇同一天不同時間段的實現(xiàn)代碼,需要先在main.js中導(dǎo)入相應(yīng)代碼,代碼簡單易懂,需要的朋友可以參考下
    2024-02-02
  • vue keep-alive 動態(tài)刪除組件緩存的例子

    vue keep-alive 動態(tài)刪除組件緩存的例子

    今天小編就為大家分享一篇vue keep-alive 動態(tài)刪除組件緩存的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-11-11
  • element-ui 彈窗組件封裝的步驟

    element-ui 彈窗組件封裝的步驟

    這篇文章主要介紹了element-ui 彈窗組件封裝的步驟,幫助大家更好的理解和使用vue框架,感興趣的朋友可以了解下
    2021-01-01

最新評論