vue canvas绘制点、直线、矩形、圆、多边形;以及点击选中高亮;拖拽、放大缩小;明暗度调节

发布时间:2023年12月17日

canvas 元素

<!--画布-->
<canvas
  id="myCanvas"
  :height="canvasSize.height"
  :width="canvasSize.width"
  :style="{
    cursor: isDragging ? 'grab' : 'default',
    top: canvasPosition.y + 'px',
    left: canvasPosition.x + 'px',
    '-webkit-filter': 'grayscale(' + shading + '%)'
  }"
  @mousewheel="handleMouseWheel"
  @contextmenu="handleContextmenu"
  @mousedown="handleMouseStart"
  @mousemove="handleMouseMove"
  @mouseup="handleMouseEnd"
></canvas>

定义画布变量以及其它变量

<script>
let ctx = ''
export default {
	data(){
		return{
		  imgSize: { height: "", width: "" }, //图片原始尺寸
	      imgZoom: 1, //图片缩放倍数(默认一倍)
	      canvasSize: { height: "", width: "" }, //画布尺寸
	      canvasPosition: { x: "", y: "" }, //画布位置
	      canvasMouseStart: { x: "", y: "" }, //画布中鼠标开始点击位置
	      isMouseDown: false, //鼠标按下状态
	      dragStart: { x: "", y: "" }, //开始拖拽的位置
	      currentDrawData: {}, // 当前绘图数据
	      currentBgImg: "", // 当前加载的背景图
		}
	}
}
</script>

获取画布地址且初始化画布

// 必须异步加载图片
loadBgImg(markImg) {
  let img = new Image(); //创建img标签
  img.src = markImg; // 后台返回完成地址
  // img.src = this.baseUrl + markImg; // 需要手动添加服务器地址
  return new Promise((resolve, reject) => {
    img.onload = () => {
      resolve(img); //返回标签
    };
    img.onerror = (err) => {
      reject(err);
    };
  });
},
// 获取所有的图片以及当前图片
getPhoto() {
  this.resetData(); // 重置
  this.canvasLoading = true;
  this.imgZoom = 1
  this.bannerList.map((item, index) => {
    if(item.ImgId == this.currentImageId) {
      this.curIndex = this.currentImageId;
      // 当前canvas图片的全部信息
      this.currentData = item;
      this.bannerListNew = this.bannerList.slice(index).concat(this.bannerList.slice(0, index));  // 当期激活的
      //加载背景图片
      this.loadBgImg(this.currentData.ImgPath).then(async (img) => {
        this.currentBgImg = img; //存下加载完成后的背景图
        await this.initCanvas(img); //图片加载完后初始化画布
        await this.getDefectTips(this.currentImageId);
      });
      this.currentModel = {}; //默认绘图模式
    }
  })
},
// 初始化画布
async initCanvas(img) {
  let width = 0
  let height = 0
  // 按0.2比例缩放图片
  width = img.width * 0.2;
  height = img.height * 0.2;
  await (this.canvasSize = { height: height, width: width}); //通过图片尺寸设置画布尺寸
  this.imgSize = { height: height, width: width }; //记录下图片原始尺寸
  ctx = document.getElementById("myCanvas").getContext("2d"); //获取上下文
  await ctx.drawImage(img, 0, 0, width, height); //在canvas中绘制图片(图片、起始位置、绘图尺寸)
  let canvasDiv = document.getElementsByClassName("canvas-div")[0]; // 画布外层元素
  this.canvasPosition = {
     x: canvasDiv.offsetWidth / 2 - width / 2,
     y: canvasDiv.offsetHeight / 2 - height / 2 - 25,
   }; //背景居中
},
// 获取图片上缺陷的坐标
async getDefectTips(id) {
  this.tableLoading = true;
  this.tableData = [];
  await axios({
    method: "get",
    url: this.baseUrl + "/img/getImgMarks_noPa",
    params: {
      pageCurrent: this.pageParm.pageIndex,
      pageSize: this.pageParm.pageSize,
      imgId: id
    }
  }).then((res) => {
    this.canvasLoading = false;
    if(res.status == 200 && res.data.success) {
      this.tableLoading = false;
      this.tableData = res.data.data.records;
      this.pageParm.pageIndex = res.data.data.current;
      this.pageParm.total = res.data.data.total;
      // 整理数据,画框
      let obj = {
        x: 0,
        y: 0,
        x1: 0,
        y1: 0,
        markId: null,
        firstLevel: '',
        secondary: '',
        describe: '',
        defectType: "0",
        virtualBox: false
      }
      if(this.tableData.length) {
        for (let i = 0; i < this.tableData.length; i++) {
          let strObj = JSON.parse(this.tableData[i].data);
          let arr = strObj.imgData.split(',');
          let item1 = Math.ceil(arr[0]) * 2 / 10;
          let item2 = Math.ceil(arr[1]) * 2 / 10;
          let item3 = Math.ceil(arr[2]) * 2 / 10;
          let item4 = Math.ceil(arr[3]) * 2 / 10;
          obj = {
            x: item1 - item3 < 0? item1: item3,
            y: item2 - item4 < 0? item2: item4,
            x1: item3 - item1 > 0? item3: item1,
            y1: item4 - item2 > 0? item4: item2,
            markId: this.tableData[i].markId,
            firstLevel: this.tableData[i].firstLevel,
            secondary: this.tableData[i].secondary,
            describe: this.tableData[i].describe,
            defectType: this.tableData[i].defectType,
            virtualBox: this.tableData[i].virtualBox
          }
          this.drawRectangle(obj);
          // 判断markIdSel是否为空,如果有值且有相等的,则回显
          if((this.markIdSel !== '') && (this.markIdSel === obj.markId)) {
            let activeObj = {
              type: 'rectangle',
              color: 'red',
              data: [
                [obj.x, obj.y],
                [obj.x1, obj.y1]
              ],
              markId: obj.markId,
              firstLevel: obj.firstLevel,
              secondary: obj.secondary,
              describe: obj.describe,
              defectType: obj.defectType,
              virtualBox: obj.virtualBox
            }
            // 表格高亮
            let row = this.tableData.filter(item => item.markId === obj.markId)[0]
            this.$nextTick(() => {
              this.$refs.tableRef.setCurrentRow(row)
            })
            // 缺陷框高亮
            this.selectPoint(activeObj);
          }
        }
      }
    }
  }).catch(() => {
    this.tableLoading = false;
    this.canvasLoading = false;
  })
},
//生成矩形数据
drawRectangle(obj) {
  this.currentDrawData = {
    type: "rectangle",
    color: 'red',
    data: [
      [obj.x, obj.y],
      [obj.x1, obj.y1],
    ],
    markId: obj.markId,
    firstLevel: obj.firstLevel,
    secondary: obj.secondary,
    describe: obj.describe,
    defectType: obj.defectType,
    virtualBox: obj.virtualBox
  };
  this.canvasData.push(this.currentDrawData);
  // 矩形绘制
  this.drawToArr();
},
// 虚线矩形框
drawDashRect(left, top, width, height, step = 5) {
  this.drawDashLine([left, top], [left + width, top], step);
  ctx.stroke();
  this.drawDashLine([left + width, top], [left + width, top + height], step);
  ctx.stroke();
  this.drawDashLine([left + width, top + height], [left, top + height], step);
  ctx.stroke();
  this.drawDashLine([left, top + height], [left, top], step);
  ctx.stroke();
},
//通过保存的大列表绘制图形
async drawToArr() {
  ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height); //清除画布图形
  ctx.drawImage(
    this.currentBgImg,
    0,
    0,
    this.canvasSize.width,
    this.canvasSize.height
  ); //重绘背景
  for (let i = 0; i < this.canvasData.length; i++) {
    ctx.beginPath();
    ctx.strokeStyle = 'red';
    ctx.lineWidth = 3;
    if(this.canvasData[i].virtualBox) {
      // 绘制虚线矩形
      this.drawDashRect(this.canvasData[i].data[0][0]*this.imgZoom, this.canvasData[i].data[0][1]*this.imgZoom, this.canvasData[i].data[1][0]*this.imgZoom - this.canvasData[i].data[0][0]*this.imgZoom, this.canvasData[i].data[1][1]*this.imgZoom - this.canvasData[i].data[0][1]*this.imgZoom, 5);
    } else {
      // 绘制实线矩形
      ctx.strokeRect(
        this.canvasData[i].data[0][0]*this.imgZoom,
        this.canvasData[i].data[0][1]*this.imgZoom,
        this.canvasData[i].data[1][0]*this.imgZoom - this.canvasData[i].data[0][0]*this.imgZoom,
        this.canvasData[i].data[1][1]*this.imgZoom - this.canvasData[i].data[0][1]*this.imgZoom
      );
    }
  }
}

绘制点、直线、矩形、圆、多边形

// 红外 -- 画基准点
drawPoint(e) {
  let offsetX = e.offsetX * this.imgZoom;
  let offsetY = e.offsetY * this.imgZoom;
  // 四个扇形
  let num = 4;
  // 一份的弧度
  let angle = (Math.PI * 2) / num;
  /*上一次绘制的结束弧度等于当前次的起始弧度*/
  //var startAngle = 0;
  for (let i = 0; i < num; i++) {
    let startAngle = i * angle;
    let endAngle = (i + 1) * angle;
    ctx.beginPath();
    if (i == 0) {
      ctx.moveTo(offsetX + 3, offsetY + 3);
      ctx.arc(offsetX + 3, offsetY + 3, 10, startAngle, endAngle);
      /*随机颜色*/
      ctx.strokeStyle = 'black';
      ctx.lineWidth = 2; // 边框宽度
      ctx.stroke();
    } else if (i == 1) {
      ctx.moveTo(offsetX - 3, offsetY + 3);
      ctx.arc(offsetX - 3, offsetY + 3, 10, startAngle, endAngle);
      /*随机颜色*/
      ctx.strokeStyle = 'black';
      ctx.lineWidth = 2; // 边框宽度
      ctx.stroke();
    } else if (i == 2) {
      ctx.moveTo(offsetX - 3, offsetY - 3);
      ctx.arc(offsetX - 3, offsetY - 3, 10, startAngle, endAngle);
      /*随机颜色*/
      ctx.strokeStyle = 'black';
      ctx.lineWidth = 2; // 边框宽度
      ctx.stroke();
    } else {
      ctx.moveTo(offsetX + 3, offsetY - 3);
      ctx.arc(offsetX + 3, offsetY - 3, 10, startAngle, endAngle);
      /*随机颜色*/
      ctx.strokeStyle = 'black';
      ctx.lineWidth = 2; // 边框宽度
      ctx.stroke();
    }
  }
  // 直线
  ctx.beginPath(); //新建路径
  ctx.moveTo(offsetX - 20, offsetY); //直线起点 x
  ctx.lineTo(offsetX + 20, offsetY); //绘直线至(x,y)坐标
  ctx.strokeStyle = "black";
  ctx.stroke(); //绘制线条
  // 竖线
  ctx.beginPath(); //新建路径
  ctx.moveTo(offsetX, offsetY - 20); //直线起点 x
  ctx.lineTo(offsetX, offsetY + 20); //绘直线至(x,y)坐标
  ctx.strokeStyle = "black";
  ctx.stroke(); //绘制线条
},
// 红外-- 画直线
drawBeeline(e) {
  ctx.beginPath();
  ctx.strokeStyle = 'black';
  ctx.lineWidth = 2;
  ctx.moveTo(this.canvasMouseStart.x, this.canvasMouseStart.y); //画笔移动至(x,y)坐标
  ctx.lineTo(e.offsetX, e.offsetY); //绘直线至(x,y)坐标
  ctx.stroke();
  //生成直线绘图数据
  this.currentDrawDataNewBeeline = {
    type: "beeline",
    color: 'black',
    data: [
      [this.canvasMouseStart.x, this.canvasMouseStart.y],
      [e.offsetX, e.offsetY],
    ],
  };
},
//画矩形
drawRectangleNew(e) {
  ctx.beginPath();
  ctx.strokeStyle = 'red';
  ctx.lineWidth = 2;
  //绘制矩形边框
  ctx.strokeRect(
    this.canvasMouseStart.x,
    this.canvasMouseStart.y,
    e.offsetX - this.canvasMouseStart.x,
    e.offsetY - this.canvasMouseStart.y
  );
  //生成矩形数据
  this.currentDrawData = {
    type: "rectangle",
    color: 'red',
    data: [
      [this.canvasMouseStart.x, this.canvasMouseStart.y],
      [e.offsetX, e.offsetY],
    ]
  };
},
//画圆
drawCircle(e) {
  this.canvasMousePosition = {
    x: e.offsetX,
    y: e.offsetY
  };
  let { x, y } = this.canvasMouseStart;
  let r = Math.round(
    Math.sqrt(
      (e.offsetX - x) * (e.offsetX - x) + (e.offsetY - y) * (e.offsetY - y)
    )
  );
  ctx.beginPath(); //新建路径
  ctx.arc(x, y, r, 0, 2 * Math.PI);
  ctx.strokeStyle = 'red'; //线条颜色
  ctx.stroke(); //绘制线条
  //生成点绘图数据
  this.currentDrawData = {
    type: "circle",
    data: [[x, y]],
    r: r,
    color: this.currentColor.color
  };
},
//画多边形
drawPolygon(e) {
  ctx.beginPath();
  ctx.strokeStyle = this.currentColor.color;
  ctx.moveTo(this.canvasMouseStart.x, this.canvasMouseStart.y);
  ctx.lineTo(e.offsetX, e.offsetY);
  ctx.stroke();
}

鼠标点击 – 判断是绘制开始选中

//鼠标按下事件
handleMousedown(e) {
  if (e.button == 0 && e.ctrlKey == true) {
    this.isDrag = true; //左键按下并且按下ctrl键 ,打开拖拽
    let el = document.getElementById("myCanvas");
    this.dragStart = {
      x: el.offsetLeft - e.screenX,
      y: el.offsetTop - e.screenY
    }; //记录下开始拖拽的偏移量
    return;
  }else if(e.button == 0 && JSON.stringify(this.currentModel) === "{}" && e.ctrlKey == false){
    console.log(this.canvasData);
    // 点击区域范围 是否有标注 待优化
    for (let index = 0; index < this.canvasData.length; index++) {
      if(this.canvasData[index].type == 'point'){ // 点
        let dis = Math.sqrt( (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) * (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) + (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom) * (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom)) 
        if(dis <= 10 * this.imgZoom){
          this.selectPoint('item')
          this.selectPoint(this.canvasData[index])
          return
        }else{
          this.selectPoint('item')
        }
      }else if(this.canvasData[index].type == 'rectangle'){ // 矩形
        // 还要判断最后的对角在哪
        // const isInside = (point, rect) => point.x > rect.left && point.x < rect.right && point.y > rect.top && point.y < rect.bottom;
        if(e.offsetX > this.canvasData[index].data[0][0] * this.imgZoom
        && e.offsetX < this.canvasData[index].data[0][0] * this.imgZoom + (this.canvasData[index].data[1][0] - this.canvasData[index].data[0][0] * this.imgZoom ) 
        && e.offsetY > this.canvasData[index].data[0][1] * this.imgZoom
        && e.offsetY < this.canvasData[index].data[0][1] * this.imgZoom + (this.canvasData[index].data[1][1] - this.canvasData[index].data[0][1] * this.imgZoom)){
          this.selectPoint('item')
          this.selectPoint(this.canvasData[index])
          return
        }else{
          this.selectPoint('item')
        }
      }else if(this.canvasData[index].type == 'circle'){ // 圆
        // 第一种方法
        // let ins = Math.sqrt( (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) * (e.offsetX - this.canvasData[index].data[0][0] * this.imgZoom) + (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom) * (e.offsetY - this.canvasData[index].data[0][1] * this.imgZoom))
        // if(ins <= this.canvasData[index].r * this.imgZoom){
        //   this.selectPoint('item')
        //   this.selectPoint(this.canvasData[index])
        //   return
        // } else {
        //   this.selectPoint('item')
        // }
        // 第二种方法
        // 判断点击位置是否在圆内
        const isInsideCircle = this.isPointInsideCircle(this.canvasData[index].data[0][0] * this.imgZoom, this.canvasData[index].data[0][1] * this.imgZoom, this.canvasData[index].r * this.imgZoom, e.offsetX, e.offsetY);
        if (isInsideCircle) {
          // 点击位置在圆内
          this.selectPoint('item')
          this.selectPoint(this.canvasData[index])
          return;
        } else {
          // 点击位置不在圆内,进行相应的处理
          this.selectPoint('item')
        }
      } else if(this.canvasData[index].type == 'beeline') { // 直线
        // 判断点击点是否在直线容差范围内
        const isWithinToleranceRange = this.isWithinTolerance(
          this.canvasData[index].data[0][0] * this.imgZoom,
          this.canvasData[index].data[0][1] * this.imgZoom,
          this.canvasData[index].data[1][0] * this.imgZoom,
          this.canvasData[index].data[1][1] * this.imgZoom,
          e.offsetX,
          e.offsetY,
          2 // 容差值
        );
        if (isWithinToleranceRange) {
          // 点击点在直线容差范围内
          this.selectPoint('item')
          this.selectPoint(this.canvasData[index])
          return;
        } else {
          // 点击点不在直线容差范围内,进行相应的处理
          this.selectPoint('item')
        }
      } else if(this.canvasData[index].type == 'polygon') {
        // 判断点击位置是否在多边形内
        const isInsidePolygon = this.isPointInsidePolygon(this.canvasData[index].data, e.offsetX, e.offsetY);
        if (isInsidePolygon) {
          // 点击位置在多边形内
          console.log(this.canvasData[index]);
          this.selectPoint('item')
          this.selectPoint(this.canvasData[index])
          return;
        } else {
          // 点击位置不在多边形内,进行相应的处理
          this.selectPoint('item')
        }
      }
    }
  }
  if (e.button !== 2) {
    return; // 左键绘图
  }
  this.isMouseDown = true; // 打开鼠标状态
  //获取画布中鼠标开始点击位置
  this.canvasMouseStart = {
    x: e.offsetX,
    y: e.offsetY
  };
},

鼠标移动 – 绘制

//鼠标移动事件
async handleMousemove(e) {
  if (this.isDrag) {
    this.mouseDrag(e); //处理拖拽
    return;
  }
  this.isMsg = true;
  //获取屏幕中鼠标位置(显示实时坐标)
  this.mousePosition = {
    x: e.pageX,
    y: e.pageY
  };
  //获取画布中鼠标位置
  this.canvasMousePosition = {
    x: e.offsetX,
    y: e.offsetY
  };
  //判断是否超出边界
  if (e.offsetX < 0 || e.offsetY < 0 || e.offsetX == 0 || e.offsetY == 0) {
    this.isMsg = false;
    this.isMouseDown = false; //关闭鼠标状态
  }
  //判断鼠标状态是否打开
  if (!this.isMouseDown) {
    return;
  }
  ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height); //清除画布后立刻重新绘制视觉上形成动画
  await ctx.drawImage(
    this.currentBgImg,
    0,
    0,
    this.canvasSize.width,
    this.canvasSize.height
  ); //在canvas中绘制图片
  await this.drawToArr(); //重绘列表数据
  //绘制点
  if (this.currentModel.model == "point") {
    return;
  }
  //绘制直线
  if (this.currentModel.model == "beeline") {
    this.drawBeeline(e);
  }
  //绘制矩形
  if (this.currentModel.model == "rectangle") {
    this.drawRectangle(e);
  }
  //绘制圆形
  if (this.currentModel.model == "circle") {
    this.drawCircle(e);
  }
},

鼠标松开 – 还原真实坐标,添加数据到总数居,多边形绘制

//鼠标松开事件
handleMouseup(e) {
   if (e.button == 0) {
     this.isDrag && (this.isDrag = false); //左键松开关闭拖拽
   }
   if (e.button !== 2) {
     return; // 右键松开
   }
   //点模式的松开
   if (this.currentModel.model == "point") {
     this.drawPoint(e); //用鼠标松开时的位置画点
     this.currentDrawData.data.forEach((e) => {
       e[0] = e[0] / this.imgZoom; //将坐标数据还原至真实数据 
       e[1] = e[1] / this.imgZoom;
       // 添加 直/竖 坐标
     });
     this.canvasData.push(this.currentDrawData); //添加当前绘图数据至大列表
   }
   // 矩形
   if(this.currentModel.model == "rectangle") {
     this.currentDrawData.data.forEach((e) => {
       e[0] = e[0] / this.imgZoom; //还原真实坐标
       e[1] = e[1] / this.imgZoom;
     });
     this.canvasData.push(this.currentDrawData); //添加当前绘图数据
   }
   //线模式、直线模式、圆形
   if (
     this.currentModel.model == "line" ||
     this.currentModel.model == "beeline" || 
     this.currentModel.model == "circle"
   ) {
     this.currentDrawData.data.forEach((e) => {
       e[0] = e[0] / this.imgZoom; //还原真实坐标
       e[1] = e[1] / this.imgZoom;
     });
     this.currentModel.model == "circle" &&
       (this.currentDrawData.r = this.currentDrawData.r / this.imgZoom); //圆形模式需要处理半径
     this.canvasData.push(this.currentDrawData); //添加当前绘图数据
   }
   //多边形模式的松开
   if (this.currentModel.model == "polygon") {
     this.constructPolygonData(e); //构造多边形数据
     this.drawToArr(); //多边形模式中每次鼠标松开后都需要重绘列表数据
     //更新多边形画线时起点位置
     this.canvasMouseStart = {
       x: e.offsetX / this.imgZoom, //还原真实坐标
       y: e.offsetY / this.imgZoom
     };
   }
   this.isMouseDown = false; //关闭鼠标状态
   this.canvasMousePosition = {
     x: e.offsetX, //更新位置
     y: e.offsetY
   };
 },

多边形添加数据

//生成多边形数据
constructPolygonData(e) {
  if (this.polygonTempList.data) {
    let oldPointX =
      this.polygonTempList.data[this.polygonTempList.data.length - 1][0];
    let oldPointY =
      this.polygonTempList.data[this.polygonTempList.data.length - 1][1];
    let newPointX = e.offsetX / this.imgZoom; //计算出真实坐标
    let newPointY = e.offsetY / this.imgZoom;
    //多边形需防止坐标重复
    if (oldPointX !== newPointX || oldPointY !== newPointY) {
      //非第一次松开直接push多边形点列表
      this.polygonTempList.data.push([newPointX, newPointY]);
    }
  } else {
    //第一次松开则构造完整数据
    this.polygonTempList = {
      type: "polygon",
      color: this.currentColor.color,
      data: [[e.offsetX / this.imgZoom, e.offsetY / this.imgZoom]]
    };
  }
}

选中高亮

// 计算点到直线的距离
calculateDistanceToLine(x1, y1, x2, y2, x, y) {
   const A = y2 - y1;
   const B = x1 - x2;
   const C = x2 * y1 - x1 * y2;
   return Math.abs(A * x + B * y + C) / Math.sqrt(A * A + B * B);
 },
 // 判断点击点是否在直线容差范围内 -- 5px
 isWithinTolerance(x1, y1, x2, y2, x, y, tolerance) {
   const distance = this.calculateDistanceToLine(x1, y1, x2, y2, x, y);
   return distance <= tolerance;
 },
 // 判断是否点中多边形
 isPointInsidePolygon(vertices, x, y) {
   let intersections = 0;
   // 判断射线与多边形的交点数量
   for (let i = 0; i < vertices.length; i++) {
     const vertex1 = vertices[i];
     const vertex2 = vertices[(i + 1) % vertices.length];
     if (((vertex1[1] > y) != (vertex2[1] > y)) && (x < (vertex2[0] - vertex1[0]) * (y - vertex1[1]) / (vertex2[1] - vertex1[1]) + vertex1[0])) {
       intersections++;
     }
   }
   // 奇数个交点则点在多边形内
   return (intersections % 2) === 1;
 },
 // 判断是否点中圆
 isPointInsideCircle(centerX, centerY, radius, x, y) {
   const distance = Math.sqrt(Math.pow(x - centerX, 2) + Math.pow(y - centerY, 2));
   return distance <= radius;
 },
// 选中标注
selectPoint(item){
 if(item == 'item'){
   this.drawToArr();
   this.isSelect = true;
 }else if(this.isSelect){
   if(item.type == 'point'){
     ctx.beginPath();
     ctx.arc(
       item.data[0][0] * this.imgZoom,
       item.data[0][1] * this.imgZoom,
       20 * this.imgZoom,
       0 * this.imgZoom,
       2 * Math.PI
     );
     // ctx.strokeStyle = item.color;
     ctx.strokeStyle = "yellow";
     ctx.stroke();
   }else if(item.type == 'rectangle'){
     ctx.beginPath();
     // ctx.strokeStyle = this.currentColor.color;
     ctx.strokeStyle = "yellow"
     //绘制矩形边框
     ctx.strokeRect(
       (item.data[0][0] - 3) * this.imgZoom,
       (item.data[0][1] - 3) * this.imgZoom,
       (item.data[1][0] - item.data[0][0] + 6) * this.imgZoom,
       (item.data[1][1] - item.data[0][1] + 6) * this.imgZoom
     );
   }else if(item.type == 'beeline'){
     ctx.beginPath();
     ctx.moveTo(item.data[0][0] * this.imgZoom, item.data[0][1] * this.imgZoom);
     ctx.lineTo(item.data[1][0] * this.imgZoom, item.data[1][1] * this.imgZoom);
     ctx.strokeStyle = 'yellow';
     ctx.stroke();
   } else if(item.type == 'circle') {
     ctx.beginPath();
     ctx.arc(
       item.data[0][0] * this.imgZoom,
       item.data[0][1] * this.imgZoom,
       item.r * this.imgZoom,
       0 * this.imgZoom,
       2 * Math.PI
     );
     ctx.strokeStyle = "yellow";
     ctx.stroke();
   } else if(item.type == 'polygon') {
     console.log(item, this.polygonTempList.data);
     //判断多边形临时列表是否有数据
     if (item.data && item.data.length > 1) {
       ctx.beginPath();
       ctx.strokeStyle = 'yellow';
       ctx.moveTo(
         item.data[0][0] * this.imgZoom,
         item.data[0][1] * this.imgZoom
       ); //起始点
       //遍历多边形点列表连续绘制
       item.data.forEach((p) => {
         ctx.lineTo(p[0] * this.imgZoom, p[1] * this.imgZoom);
       });
       //通过状态判断多边形是否闭合
       if (item.isClose) {
         ctx.closePath(); //闭合
       }
       ctx.stroke();
     }
   }
   this.isSelect = false;
 }
},

总数据绘制

//通过保存的大列表绘制图形
async drawToArr() {
 ctx.clearRect(0, 0, this.canvasSize.width, this.canvasSize.height); //清除画布图形
 ctx.drawImage(
   this.currentBgImg,
   0,
   0,
   this.canvasSize.width,
   this.canvasSize.height
 ); //重绘背景
 //遍历大列表开始绘制
 await this.canvasData.forEach((e) => {
   //绘制点
   // console.log(e)
   if (e.type == "point") {
     ctx.beginPath();
     ctx.arc(
       e.data[0][0] * this.imgZoom,
       e.data[0][1] * this.imgZoom,
       10 * this.imgZoom,
       0 * this.imgZoom,
       2 * Math.PI
     );
     // ctx.fillStyle = e.color;
     ctx.strokeStyle = e.color;
     // ctx.fill();
     ctx.stroke();

     // let num  = 4;
     // // 一份的弧度
     // let angle = Math.PI * 2 / num;
     // /*上一次绘制的结束弧度等于当前次的起始弧度*/
     // //var startAngle = 0;
     // for (let i = 0; i < num; i++) {
     //     let startAngle = i * angle;
     //     let endAngle = (i + 1) * angle;
     //     ctx.beginPath();
     //     if(i == 0){
     //       ctx.moveTo(e.data[0][0] + 3, e.data[0][1] + 3);
     //       ctx.arc(e.data[0][0] + 3, e.data[0][1] + 3, 10, startAngle, endAngle);
     //       /*随机颜色*/
     //       ctx.fillStyle = this.currentColor.color;
     //       ctx.fill();
     //     }else if(i == 1){
     //       ctx.moveTo(e.data[0][0] - 3, e.data[0][1] + 3);
     //       ctx.arc(e.data[0][0] - 3, e.data[0][1] + 3, 10, startAngle, endAngle);
     //       /*随机颜色*/
     //       ctx.fillStyle = this.currentColor.color;
     //       ctx.fill();
     //     }else if(i == 2) {
     //       ctx.moveTo(e.data[0][0] - 3, e.data[0][1] - 3);
     //       ctx.arc(e.data[0][0] - 3, e.data[0][1] - 3, 10, startAngle, endAngle);
     //       /*随机颜色*/
     //       ctx.fillStyle = this.currentColor.color;
     //       ctx.fill();
     //     }else{
     //       ctx.moveTo(e.data[0][0] +3, e.data[0][1] -3);
     //       ctx.arc(e.data[0][0] + 3, e.data[0][1] - 3, 10, startAngle, endAngle);
     //       /*随机颜色*/
     //       ctx.fillStyle = e.color;
     //       ctx.fill();
     //     }
     // }
     // 直线
     ctx.beginPath(); //新建路径
     ctx.moveTo(e.data[1][0] * this.imgZoom,e.data[1][1] * this.imgZoom); //直线起点 x
     ctx.lineTo(e.data[2][0] * this.imgZoom,e.data[2][1] * this.imgZoom); //绘直线至(x,y)坐标
     ctx.strokeStyle = e.color;
     ctx.stroke(); //绘制线条
     // 竖线
     ctx.beginPath(); //新建路径
     ctx.moveTo(e.data[3][0] * this.imgZoom,e.data[3][1] * this.imgZoom); //直线起点 x
     ctx.lineTo(e.data[4][0] * this.imgZoom,e.data[4][1] * this.imgZoom); //绘直线至(x,y)坐标
     ctx.strokeStyle = e.color;
     ctx.stroke(); //绘制线条
   }
   //绘制直线
   if (e.type == "beeline") {
     ctx.beginPath();
     ctx.moveTo(e.data[0][0] * this.imgZoom, e.data[0][1] * this.imgZoom);
     ctx.lineTo(e.data[1][0] * this.imgZoom, e.data[1][1] * this.imgZoom);
     ctx.strokeStyle = e.color;
     ctx.stroke();
   }
   //绘制矩形
   if (e.type == "rectangle") {
     ctx.beginPath();
     ctx.strokeStyle = e.color;
     ctx.strokeRect(
       e.data[0][0] * this.imgZoom,
       e.data[0][1] * this.imgZoom,
       e.data[1][0] * this.imgZoom - e.data[0][0] * this.imgZoom,
       e.data[1][1] * this.imgZoom - e.data[0][1] * this.imgZoom
     ); //绘制矩形边框
   }
   //绘制多边形
   if (e.type == "polygon") {
     ctx.beginPath();
     ctx.strokeStyle = e.color;
     ctx.moveTo(e.data[0][0] * this.imgZoom, e.data[0][1] * this.imgZoom); //起始点
     //遍历多边形点列表连续绘制
     e.data.forEach((p) => {
       ctx.lineTo(p[0] * this.imgZoom, p[1] * this.imgZoom);
     });
     ctx.stroke();
   }
   //绘制圆形
   if (e.type == "circle") {
     ctx.beginPath();
     ctx.arc(
       e.data[0][0] * this.imgZoom,
       e.data[0][1] * this.imgZoom,
       e.r * this.imgZoom,
       0,
       2 * Math.PI
     );
     ctx.strokeStyle = e.color;
     ctx.stroke(); //绘制线条
   }
 });
 //判断多边形临时列表是否有数据
 if (this.polygonTempList.data && this.polygonTempList.data.length > 1) {
   ctx.beginPath();
   ctx.strokeStyle = this.polygonTempList.color;
   ctx.moveTo(
     this.polygonTempList.data[0][0] * this.imgZoom,
     this.polygonTempList.data[0][1] * this.imgZoom
   ); //起始点
   //遍历多边形点列表连续绘制
   this.polygonTempList.data.forEach((p) => {
     ctx.lineTo(p[0] * this.imgZoom, p[1] * this.imgZoom);
   });
   //通过状态判断多边形是否闭合
   if (this.polygonTempList.isClose) {
     ctx.closePath(); //闭合
   }
   ctx.stroke();
 }
},

拖拽

//鼠标拖拽
mouseDrag(e) {
  this.canvasPosition.x = e.screenX + this.dragStart.x; //计算出画布位置
  this.canvasPosition.y = e.screenY + this.dragStart.y;
},

放大缩小

//鼠标滚动事件(wheelDelta值上滚为负下滚为正)
async handleMouseWheel(e) {
  let el = document.getElementById("myCanvas");
  let oldX = el.offsetLeft; //旧位置
  let oldY = el.offsetTop;
  await this.changeCanvas(e, oldX, oldY); //改变画布
  this.drawToArr(); // 重绘列表数据
},
//滚动时改变画布
changeCanvas(e, oldX, oldY) {
  let zoomSpeed = 0.2; //缩放速度
  e.wheelDelta > 0 && (zoomSpeed = 2 - zoomSpeed); // 判断放大与缩小
  let posX = e.offsetX; //获取鼠标定点的位置(鼠标在图片上的位置)
  let posY = e.offsetY;
  let oldImgZoom = this.imgZoom; //记录下旧的图片缩放倍数
  this.imgZoom = this.imgZoom * zoomSpeed; //更新缩放倍数
  let minZoom = 0.3; //最小缩放倍数
  let maxZoom = 3; //最大缩放倍数
  this.imgZoom > maxZoom && (this.imgZoom = maxZoom); //限制缩放倍数
  this.imgZoom < minZoom && (this.imgZoom = minZoom);
  this.imgZoom = Number(this.imgZoom.toFixed(2));
  zoomSpeed = this.imgZoom / oldImgZoom; //更新缩放速度
  let height = Math.round(this.imgSize.height * this.imgZoom); //计算画布新宽高(原始宽高乘缩放倍数)
  let width = Math.round(this.imgSize.width * this.imgZoom);
  let newX = oldX + Math.round(posX * (1 - zoomSpeed)); //计算画布新位置(旧位置加偏移量)
  let newY = oldY + Math.round(posY * (1 - zoomSpeed));
  this.canvasSize = { height: height, width: width }; //更新画布尺寸
  this.canvasPosition = { x: newX, y: newY }; //更新画布位置
},

明暗度调节 – 动态修改grayscale的值

<el-slider v-model="shading" :show-tooltip="false"></el-slider>

保护好自己的原厂配件

文章来源:https://blog.csdn.net/agua001/article/details/134967920
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。