美文网首页
图片上画不规则多边形区域可拖动

图片上画不规则多边形区域可拖动

作者: yonglei_shang | 来源:发表于2023-04-20 14:13 被阅读0次
    <template>
      <div class="set-area-root">
        <el-dialog
          title="设置判别区域"
          :visible="dialogVisible"
          width="50%"
          @close="handleClose"
        >
          <div class="dialog-container">
            <div
              class="canvas-box"
              @mousedown="boxMouseDown"
              @mousemove="boxMouseMove"
              @mouseup="boxMouseUp"
            >
              <img :src="imgUrl" alt="" />
              <canvas id="rect_canvas" @mousedown.stop="mousedownHandle"></canvas>
              <div
                v-for="pointItem in points"
                :key="pointItem.id"
                class="point-item"
                :data-id="pointItem.id"
                :style="{
                  left: pointItem.x - 5 + 'px',
                  top: pointItem.y - 5 + 'px',
                }"
              ></div>
            </div>
    
            <div class="btns">
              <el-button @click="handleClose">取消</el-button>
              <el-button @click="resetClick">重置</el-button>
              <el-button type="primary" @click="sureClick">确定</el-button>
            </div>
          </div>
        </el-dialog>
      </div>
    </template>
    
    <script>
    export default {
      props: {
        dialogVisible: {
          type: Boolean,
          default: false,
        },
        pointList: {
          type: Array,
          default: () => [],
        },
      },
      data() {
        return {
          imgUrl:
            'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg',
          ctx: null,
          canvasDom: null,
          imgNaturalSize: {},
          points: [],
          activPoint: {}, // 当前点击的点
          moveStart: false,
        };
      },
      watch: {
        dialogVisible: {
          handler(newval) {
            if (newval) {
              if (this.pointList.length) {
                this.points = this.calcXY(1, this.pointList);
              }
              this.$nextTick(() => {
                this.init();
              });
            }
          },
          immediate: true,
        },
      },
      methods: {
        handleClose() {
          this.$emit('update:dialogVisible', false);
          this.clearRect();
          this.points = [];
        },
        init() {
          this.canvasDom = document.querySelector('#rect_canvas');
          this.canvasDom.width = this.canvasDom.clientWidth;
          this.canvasDom.height = this.canvasDom.clientHeight;
          this.ctx = this.canvasDom.getContext('2d');
          this.getImgSize();
          // 如果是回显
          if (this.points.length) {
            this.points.forEach((pointItem) => {
              this.drawPoint(pointItem.x, pointItem.y);
            });
            this.drawLine();
          }
        },
        // 获取图片实际尺寸
        getImgSize() {
          let img = new Image();
          img.onload = () => {
            this.imgNaturalSize = {
              width: img.naturalWidth,
              height: img.naturalHeight,
            };
          };
          img.src = this.imgUrl;
        },
        // 绘制点
        drawPoint(x, y) {
          this.ctx.beginPath();
          this.ctx.arc(x, y, 5, 0, 2 * Math.PI);
          this.ctx.fillStyle = 'red';
          this.ctx.fill();
          this.ctx.closePath();
        },
        // 将点相连接
        drawLine() {
          let firstPoint = this.points[0];
          this.ctx.beginPath();
          this.ctx.strokeStyle = 'red';
          this.ctx.moveTo(firstPoint.x, firstPoint.y);
          this.points.forEach((item) => {
            this.ctx.lineTo(item.x, item.y);
            this.ctx.stroke();
          });
          this.ctx.lineTo(firstPoint.x, firstPoint.y);
          this.ctx.stroke();
          this.ctx.closePath();
        },
        // claer canvas
        clearRect() {
          this.ctx.clearRect(
            0,
            0,
            this.canvasDom.clientWidth,
            this.canvasDom.clientHeight
          );
        },
        /**
         * 根据当前canvas的宽度和高度与标点时的宽度高度对比就算 x,y
         * @param {number} type 1,代表计算页面上显示的x, y; 2,代表计算图片原尺寸上 x, y坐标
         * @param {array} list 点的集合
         */
        calcXY(type, list) {
          let newList = JSON.parse(JSON.stringify(list));
          newList.forEach((element) => {
            let nowWidth = this.canvasDom.clientWidth;
            let nowHeight = this.canvasDom.clientHeight;
            if (type === 1) {
              let { imgNaturalWidth, imgNaturalHeight } = element;
              element.x = Math.round((nowWidth / imgNaturalWidth) * element.x);
              element.y = Math.round((nowHeight / imgNaturalHeight) * element.y);
            } else if (type === 2) {
              let { width, height } = this.imgNaturalSize;
              element.x = Math.round((width / nowWidth) * element.x);
              element.y = Math.round((height / nowHeight) * element.y);
              element.imgNaturalWidth = width;
              element.imgNaturalHeight = height;
            }
          });
          return newList;
        },
        // canvas mousedown event
        mousedownHandle(e) {
          let event = e || window.event;
          event.preventDefault();
          if (this.points.length >= 4) {
            this.showNotify('只能选择4个点', 'warning');
            return;
          }
          let postion = {
            x: event.offsetX,
            y: event.offsetY,
            id: this.points.length,
          };
          this.drawPoint(postion.x, postion.y);
          this.points.push(postion);
          if (this.points.length === 4) this.drawLine();
        },
        // box mousedown event
        boxMouseDown(e) {
          if (this.points.length !== 4) {
            this.showNotify('请确定是否选择了4个点', 'warning');
            return;
          }
          let params = e.target.dataset;
          if (params.id) {
            this.activPoint = this.points.find((el) => el.id === Number(params.id));
            this.moveStart = true;
          }
        },
        // box mousemove event
        boxMouseMove(e) {
          if (this.moveStart) {
            let clientx = e.clientX;
            let clienty = e.clientY;
            let { left, top, width, height } =
              this.canvasDom.getBoundingClientRect();
            let x = Math.round(clientx - left) < 0 ? 0 : Math.round(clientx - left);
            let y = Math.round(clienty - top) < 0 ? 0 : Math.round(clienty - top);
            this.activPoint.x = x > width ? Math.round(width) : x;
            this.activPoint.y = y > height ? Math.round(height) : y;
            this.clearRect();
            this.points.forEach((pointItem) => {
              this.drawPoint(pointItem.x, pointItem.y);
            });
            this.drawLine();
          }
        },
        // box mouseup event
        boxMouseUp() {
          this.activPoint = {};
          this.moveStart = false;
        },
        // 提示框
        showNotify(message, type) {
          this.$notify({
            title: '提示',
            message,
            type,
          });
        },
        // reset
        resetClick() {
          this.clearRect();
          this.points = [];
          this.init();
        },
        // sure
        sureClick() {
          console.log(this.calcXY(2, this.points), this.points);
        },
      },
    };
    </script>
    
    <style lang="scss" scoped>
    .dialog-container {
      text-align: center;
      .canvas-box {
        position: relative;
        width: 100%;
        height: 500px;
        canvas {
          position: absolute;
          left: 0;
          top: 0;
          width: 100%;
          height: 100%;
          z-index: 20;
        }
        & > img {
          position: absolute;
          left: 0;
          top: 0;
          width: 100%;
          height: 100%;
          z-index: 1;
        }
        .point-item {
          position: absolute;
          width: 10px;
          height: 10px;
          border-radius: 50%;
          background: transparent;
          cursor: pointer;
          z-index: 1111;
        }
      }
      .btns {
        text-align: center;
        margin-top: 12px;
      }
    }
    </style>
    

    效果图:


    image.png

    相关文章

      网友评论

          本文标题:图片上画不规则多边形区域可拖动

          本文链接:https://www.haomeiwen.com/subject/wsirjdtx.html