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

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

作者: 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