使用canvas绘制椭圆,在椭圆上自由绘制并引入标注线和标注文字

内容分享2小时前发布
0 0 0


/**
 * @Author: dingwj
 * @Date: 2025-10-27 09:00:00
 * @Description: 绘制描述处理逻辑
 * @俩个或多个canvas同事处理绘制,撤销上一步,暂存绘制数据
 **/
import { Message } from "element-ui";
import { MessageBox } from "element-ui";
// 选项式API写法(兼容Vue2/Vue3)
export default {
  data() {
    return {
      canvasJmRight: {},
      ctxRight: {},
      imageObjRight: null,
 
      canvasJmLefts: {},
      ctxLefts: {},
      imageObjLefts: null,
 
      drawingHistoryRight: [],
      pendingShapesRight: [],
      currentShapeRight: null,
 
      drawingHistoryLefts: [],
      pendingShapesLefts: [],
      currentShapeLefts: null,
 
      centerRight: { x: 320 / 2, y: 200 / 2 },
      imageRadiusRight: 100, //200/2=100
      centerLefts: { x: 320 / 2, y: 200 / 2 },
      imageRadiusLefts: 100, //200/2=100
 
      isDrawing: false,
      isDwjPoint: null,
      fontStyle: "normal 400 16px PingFangSC",
      freeLine: {
        freeWidth: 5,//自由圆宽度
        lineWidth: 4 //标注线宽度
      }
    };
  },
  methods: {
    // 初始化-图片方法预处理
    initLoadingCanvasCtx() {
      // 初始化-图片加载方法
      this.loadingCtxImage("Right", null);
      this.loadingCtxImage("Lefts", null);
      // 鼠标事件处理方法监听
      this.canvasJmRight.addEventListener("mousedown", this.toListenerMousedown);
      this.canvasJmRight.addEventListener("mousemove", this.toListenerMousemove);
      this.canvasJmRight.addEventListener("mouseup", this.toListenerMouseup);
      this.canvasJmLefts.addEventListener("mousedown", this.toListenerMousedown);
      this.canvasJmLefts.addEventListener("mousemove", this.toListenerMousemove);
      this.canvasJmLefts.addEventListener("mouseup", this.toListenerMouseup);
      // 初始化-清除保存的缓存
      let RightCorneaData = "RightCorneaData";
      localStorage.removeItem(RightCorneaData);
      let LeftsCorneaData = "LeftsCorneaData";
      localStorage.removeItem(LeftsCorneaData);
    },
    // 左右眼参与的字段定义
    getEyeCorneaCs(zyEye, print) {
      // 打印图无输入框运动图参数
      let m = print === "print" ? "2" : "";
      return {
        canvasId: "canvasJm" + m + zyEye,
        ctxId: "ctx" + m + zyEye,
        imageObjId: "imageObj" + m + zyEye,
        centerId: "center" + m + zyEye,
        imageRadiusId: "imageRadius" + m + zyEye,
        drawingHistoryId: "drawingHistory" + zyEye,
        pendingShapesId: "pendingShapes" + zyEye,
        currentShapeId: "currentShape" + zyEye
      };
    },
    // 根据左右眼渲染眼球运动图片1
    // 填充和打印眼球运动图片通用方法
    loadingCtxImage(zyEye, print) {
      // 获取图片绘制参数填充和打印参数
      let paramsCs = this.getEyeCorneaCs(zyEye, print);
      let { canvasId, ctxId, imageObjId, centerId, imageRadiusId } = paramsCs;
      this[canvasId] = document.getElementById(canvasId);
      this[ctxId] = this[canvasId].getContext("2d");
      this[imageObjId] = new Image();
      if (zyEye === "Right") {
        if (print === "print") {
          this[imageObjId].src = require("@/assets/image/右.svg");
        } else {
          this[imageObjId].src = require("@/assets/image/眼.svg");
        }
      }
      if (zyEye === "Lefts") {
        if (print === "print") {
          this[imageObjId].src = require("@/assets/image/左.svg");
        } else {
          this[imageObjId].src = require("@/assets/image/眼.svg");
        }
      }
      this[imageObjId].onload = () => {
        let canvasW = this[canvasId].width;
        let canvasH = this[canvasId].height;
        this[centerId] = { x: canvasW / 2, y: canvasH / 2 };
        this[imageRadiusId] = (Math.min(canvasW, canvasH) / 2) - 15;
        // 将眼球运动图片绘制到画布中
        this.drawImageByCanvasImg(zyEye, print);
        // 绘制四等分标线边界线-测试用
        this.drawQuadrantLinesByDwj(zyEye, print);
      };
    },
    // 将眼球运动图片绘制到画布中
    // 填充和打印眼球运动图片通用方法
    drawImageByCanvasImg(zyEye, print) {
      // 获取图片绘制参数填充和打印参数
      let paramsCs = this.getEyeCorneaCs(zyEye, print);
      let { ctxId, imageObjId, centerId, imageRadiusId } = paramsCs;
      // 开始绘制到画布中
      this[ctxId].save();
      // 创建圆形裁剪路径(
      this[ctxId].beginPath();
      this[ctxId].arc(
        this[centerId].x,
        this[centerId].y,
        this[imageRadiusId],
        0,
        Math.PI * 2
      );
      this[ctxId].closePath();
      this[ctxId].clip();
 
      // 计算图片绘制区域(保持原始比例)
      const imgRatio = this[imageObjId].width / this[imageObjId].height;
      const diameter_zj = this[imageRadiusId] * 2;
      let drawWiddth = diameter_zj;
      let drawHeight = diameter_zj;
 
      // 根据图片比例调整绘制尺寸
      if (imgRatio > 1) {
        drawHeight = drawWiddth / imgRatio;
      } else {
        drawWiddth = drawHeight * imgRatio;
      }
 
      // 居中绘制(带10px边距)
      const drawX = this["center" + zyEye].x - drawWiddth / 2;
      const drawY = this["center" + zyEye].y - drawHeight / 2;
 
      this[ctxId].drawImage(
        this[imageObjId],
        drawX,
        drawY,
        drawWiddth,
        drawHeight
      );
      this[ctxId].restore();
    },
    // 鼠标动的元素
    getZyEyeId(e) {
      let zyEye = "Right";
      let eyeId = e.currentTarget.id;
      if (eyeId.includes("Right")) {
        zyEye = "Right";
      } else if (eyeId.includes("Lefts")) {
        zyEye = "Lefts";
      }
      return zyEye;
    },
    // 按下鼠标键时触发的事件
    toListenerMousedown(e) {
      if (!this.isDwjDraw) {
        return false;
      }
      let zyEye = this.getZyEyeId(e);
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { ctxId, currentShapeId, imageObjId } = paramsCs;
 
      if (this[imageObjId] === null) {
        return false;
      }
 
      let isOver = this.isOverstepLimit(e, zyEye);
      if (isOver === true) {
        return false;
      }
 
      this.isDrawing = true;
 
      const pos = this.getMousePos(e, zyEye);
      const showText = this.getShowText();
 
      this[currentShapeId] = {
        type: "free",
        points: [[pos.x, pos.y]],
        color: showText.lineColor,
        width: this.freeLine.freeWidth
      };
      this[ctxId].beginPath();
      this[ctxId].moveTo(pos.x, pos.y);
    },
    // 是否超出限制
    isOverstepLimit(e, zyEye) {
      let limitValue = 120;
      let valueObj = this.getDistToCenter(e, zyEye);
      let absValue = Math.abs(valueObj.x) + Math.abs(valueObj.y);
      if (limitValue < absValue) {
        return true;
      }
      return false;
    },
    // 鼠标落地到中心线的距离
    getDistToCenter(e, zyEye) {
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { centerId } = paramsCs;
      const pos = this.getMousePos(e, zyEye);
      // 计算相对于中心点的坐标位置
      const relativeX = pos.x - this[centerId].x;
      const relativeY = pos.y - this[centerId].y;
      // 可选:计算距离中心点的距离
      const distanceToCenter = Math.sqrt(relativeX * relativeX + relativeY * relativeY);
      // 在控制台或消息中显示相对坐标
      let xdjl = `相对于中心点坐标: (${relativeX}, ${relativeY}), 距离: ${distanceToCenter}`;
      console.log("图左右眼=" + zyEye + ":" + xdjl);
      return {
        x: relativeX,
        y: relativeY,
        dist: distanceToCenter
      };
    },
    // 鼠标坐标位置
    getMousePos(e, zyEye) {
      // 获取鼠标在Canvas画布上的精确坐标位置
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { canvasId } = paramsCs;
      const rect = this[canvasId].getBoundingClientRect();
      return {
        x: e.clientX - rect.left,
        y: e.clientY - rect.top
      };
    },
    // 描述文本对象
    getShowText() {
      let value = this.btnLabelValue;
      let hasData = this.options.find(p => p.value == value);
      return hasData ? hasData : this.options[0];
    },
    // 按下鼠标键滑动鼠标事件
    toListenerMousemove(e) {
      if (!this.isDwjDraw) {
        return false;
      }
      let zyEye = this.getZyEyeId(e);
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { imageObjId, currentShapeId } = paramsCs;
 
      if (this[imageObjId] === null) {
        return false;
      }
 
      if (!this.isDrawing) {
        return false;
      }
      if (!this[currentShapeId]) {
        return false;
      }
      if (this[currentShapeId].points.length < 1) {
        return false;
      }
      const pos = this.getMousePos(e, zyEye);
      this[currentShapeId].points.push([pos.x, pos.y]);
 
      this.toReDrawingCanvas(zyEye);
    },
    // 重绘画布-塞入数据
    toReDrawingCanvas(zyEye, print) {
      let paramsCs = this.getEyeCorneaCs(zyEye, print);
      let { canvasId, ctxId, imageObjId, drawingHistoryId, pendingShapesId, currentShapeId } = paramsCs;
 
      this[ctxId].clearRect(0, 0, this[canvasId].width, this[canvasId].height);
      if (this[imageObjId]) {
        this.drawImageByCanvasImg(zyEye, print);
      }
      // 绘制已确认的图形
      this[drawingHistoryId].forEach(shape => {
        this.drawFreeLine(shape, zyEye, print);
        if (shape.annotation && print !== "print") {
          this.drawAnnotation(shape, shape.annotation, zyEye, print);
        }
      });
      // 绘制待确认的图形
      this[pendingShapesId].forEach(shape => {
        this.drawFreeLine(shape, zyEye, print);
        if (shape.annotation && print !== "print") {
          this.drawAnnotation(shape, shape.annotation, zyEye, print);
        }
      });
      // 绘制当前正在绘制的图形
      if (this[currentShapeId] && print !== "print") {
        this.drawFreeLine(this[currentShapeId], zyEye, print);
      }
      // 绘制四等分标线边界线-测试用
      this.drawQuadrantLinesByDwj(zyEye);
    },
    // 绘制自由线条-不规则圆等
    drawFreeLine(shape, zyEye, print) {
      let paramsCs = this.getEyeCorneaCs(zyEye, print);
      let { ctxId } = paramsCs;
 
      // 是否填充圆边界线成圆形填充色
      this.drawFillColorToCircle(ctxId, shape)
 
      // 绘制边界线-根据鼠标移动绘制
      this[ctxId].beginPath();
      this[ctxId].strokeStyle = shape.color;
      this[ctxId].lineWidth = shape.width;
      this[ctxId].lineJoin = "round";
      this[ctxId].lineCap = "round";
 
      this[ctxId].moveTo(shape.points[0][0], shape.points[0][1]);
      for (let i = 1; i < shape.points.length; i++) {
        this[ctxId].lineTo(shape.points[i][0], shape.points[i][1]);
      }
      this[ctxId].stroke();
    },
    // 是否填充圆边界线成圆形填充色
    drawFillColorToCircle(ctxId, shape) {
      let is_start_using = 'dwj001'
      if(is_start_using === 'dwj001'){
        let color = shape.color; //线条的颜色
        let hasItem= this.options.find(p => p.lineColor === color)
        if(hasItem !== undefined && hasItem.value === '4'){
          // 判断是否为闭合图形(首尾点距离小于一定阈值)
          if (shape.points.length > 2) {
            const firstPoint = shape.points[0];
            const lastPoint = shape.points[shape.points.length - 1];
            const distance = Math.sqrt(
              Math.pow(lastPoint[0] - firstPoint[0], 2) +
              Math.pow(lastPoint[1] - firstPoint[1], 2)
            );
 
            // 如果首尾点距离小于10像素,认为是闭合图形
            if (distance < 10) {
              // 填充区域
              this[ctxId].beginPath();
              this[ctxId].moveTo(shape.points[0][0], shape.points[0][1]);
              for (let i = 1; i < shape.points.length; i++) {
                this[ctxId].lineTo(shape.points[i][0], shape.points[i][1]);
              }
              // 闭合路径以形成封闭区域
              this[ctxId].closePath();
              // 设置填充样式(使用半透明的颜色以便区分边界和填充)
              this[ctxId].fillStyle = hasItem.fillColor;
              this[ctxId].fill();
            }
          }
        }
      }
    },
    // 绘制注释线和标记文字
    drawAnnotation(shape, annotation, zyEye, print) {
      let paramsCs = this.getEyeCorneaCs(zyEye, print);
      let { ctxId } = paramsCs;
 
      const showText = this.getShowText();
      // 注解线条颜色位置
      this[ctxId].beginPath();
      this[ctxId].strokeStyle = shape.color;
      this[ctxId].lineWidth = this.freeLine.lineWidth;
      this[ctxId].moveTo(annotation.startPoint.x, annotation.startPoint.y);
      this[ctxId].lineTo(annotation.endPoint.x, annotation.endPoint.y);
      this[ctxId].stroke();
 
      // 标记文字大小颜色样式
      this[ctxId].font = this.fontStyle;
      this[ctxId].fillStyle = showText.color;
      this[ctxId].fillText(annotation.text, annotation.textPosition.x, annotation.textPosition.y);
    },
    // 按下鼠标键鼠标抬起事件
    toListenerMouseup(e) {
      if (!this.isDwjDraw) {
        return false;
      }
 
      let zyEye = this.getZyEyeId(e);
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { imageObjId, currentShapeId, pendingShapesId } = paramsCs;
 
      // 没有图片不能绘图,没有绘图线条不弹框
      if (this[imageObjId] === null) {
        return false;
      }
 
      if (!this.isDrawing) {
        this.isDrawing = false;
        return false;
      }
 
      if (!this[currentShapeId]) {
        this.isDrawing = false;
        return false;
      }
      if (this[currentShapeId].points.length < 3) {
        this.isDrawing = false;
        return false;
      }
 
      let showText = this.getShowText();
      let annotationData = this.drawAnnotationAndText(zyEye);
      // 将标注信息添加到currentShape
      this[currentShapeId].annotation = {
        startPoint: annotationData.farthestPoint,
        endPoint: annotationData.endPoint,
        textPosition: annotationData.textPosition,
        text: showText.label
      };
      // 增加个时间戳进去-肯定有大用你想想吧
      this[currentShapeId].timestamp = Date.now();
      // 增加个左右眼标志zyEye=[Right,Lefts]
      this[currentShapeId].zyEye = zyEye;
 
      if (this[currentShapeId]) {
        let currentShape = JSON.parse(JSON.stringify(this[currentShapeId]));
        this[pendingShapesId].push(currentShape);
      }
 
      // 是否超出圆形图片边界
      let isBeyond = true;
      if (isBeyond == false) {
        this.isDrawing = false;
        this[currentShapeId] = null;
        // 超出->撤销上一步绘图
        this.undoPreviousDrawing();
      } else {
        this.isDrawing = false;
        this[currentShapeId] = null;
      }
    },
    // 构建注释和文字数据节点
    drawAnnotationAndText(zyEye) {
      /*let annotationCs = {
        farthestPoint: null,
        endPoint: { x: null, y: null },
        textPosition: '文本描述',
      }*/
      let farthestPoint = this.findFarthestPoint(zyEye);
      let annotationData = this.drawAnnotationLine(farthestPoint, zyEye);
      annotationData.farthestPoint = farthestPoint;
      return annotationData;
    },
    // 找出最远点的坐标
    findFarthestPoint(zyEye) {
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { centerId, currentShapeId } = paramsCs;
 
      // 找出当前图形this.currentShape中距离中心点this.center最远的点
      let points = this[currentShapeId].points;
      let maxDist = 0;
      let farthestPoint = { x: points[0][0], y: points[0][1] };
 
      this[currentShapeId].points.forEach(p => {
        const dx = p[0] - this[centerId].x;
        const dy = p[1] - this[centerId].y;
        const dist = Math.sqrt(dx * dx + dy * dy);
        if (dist > maxDist) {
          maxDist = dist;
          farthestPoint = { x: p[0], y: p[1] };
        }
      });
 
      return farthestPoint;
    },
    // 绘制注释连线和文字描述
    drawAnnotationLine(startPoint, zyEye) {
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { ctxId, centerId, imageRadiusId } = paramsCs;
      const padding = 35; //编辑
      let extendLength = 1; //增加延伸长度
      const circle_radius = 20; //空心圆半径
      const showText = this.getShowText();
 
      // 计算方向向量
      const dx = startPoint.x - this[centerId].x;
      const dy = startPoint.y - this[centerId].y;
      const distToCenter = Math.sqrt(dx * dx + dy * dy);
      // 动态计算角度(基于象限)
      const angle = Math.atan2(dy, dx);
 
      // 计算边界点(带安全边距)
      const ratio = (this[imageRadiusId] - padding) / distToCenter;
 
      // 获取椭圆半径参数(与drawEllipseBezier方法中保持一致)
      const ellipseRadiusX = 100; // 对应 drawEllipseBezier 中的 radiusX
      const ellipseRadiusY = 60;  // 对应 drawEllipseBezier 中的 radiusY
 
      // 计算椭圆上距离中心点最远的半径长度(根据角度计算椭圆上的点)
      const ellipseRadiusAtAngle = (ellipseRadiusX * ellipseRadiusY) /
        Math.sqrt(Math.pow(ellipseRadiusX * Math.sin(angle), 2)
          + Math.pow(ellipseRadiusY * Math.cos(angle), 2));
 
      // 基于椭圆半径计算线段终点,向外延伸5px
      const endX = this[centerId].x + (ellipseRadiusAtAngle + extendLength) * Math.cos(angle);
      const endY = this[centerId].y + (ellipseRadiusAtAngle + extendLength) * Math.sin(angle);
 
      // 计算圆点中心位置
      const circleCenter = {
        x: endX + circle_radius * Math.cos(angle),
        y: endY + circle_radius * Math.sin(angle)
      };
 
      // 绘制线段-线条颜色宽度
      this[ctxId].beginPath();
      this[ctxId].strokeStyle = showText.lineColor;
      this[ctxId].lineWidth = this.freeLine.lineWidth;
      this[ctxId].moveTo(startPoint.x, startPoint.y);
      this[ctxId].lineTo(endX, endY);
      this[ctxId].stroke();
 
      // 连接长方形框文字框
      const rectWidth = 60;   // 长方形宽度
      const rectHeight = 20;  // 长方形高度
      const rectPadding = 8;  // 长方形与线段末端的间距
 
      // 计算长方形位置(基于线段末端点和角度)
      const rectCenterX = endX + (rectPadding + rectWidth/2) * Math.cos(angle);
      const rectCenterY = endY + (rectPadding + rectHeight/2) * Math.sin(angle);
 
      // 绘制空心圆-测试
      let kxy_dwj = "dwj001";
      if (kxy_dwj === "dwj002") {
        // 计算长方形左上角坐标
        const rectX = rectCenterX - rectWidth/2;
        const rectY = rectCenterY - rectHeight/2;
        // 绘制长方形框-内置文字用
        this[ctxId].beginPath();
        this[ctxId].strokeStyle = showText.lineColor;
        this[ctxId].lineWidth = 1;
        this[ctxId].strokeRect(rectX, rectY, rectWidth, rectHeight);
      }
 
      // 文字显示到长方形框中-规定文字位置
      this[ctxId].font = this.fontStyle;
      this[ctxId].fillStyle = showText.color;
      this[ctxId].textAlign = "center";
      this[ctxId].textBaseline = "middle";
      this[ctxId].fillText(showText.label, rectCenterX, rectCenterY);
 
      return {
        endPoint: { x: endX, y: endY },
        textPosition: { x: rectCenterX, y: rectCenterY }
      };
    },
    // 计算绘画的所属范围
    calcScopeOfDrawing(dx, dy) {
      if (dx < 0 && dy < 0) {
        this.isDwjPoint = "top-left";
      } else if (dx > 0 && dy < 0) {
        this.isDwjPoint = "top-right";
      } else if (dx > 0 && dy > 0) {
        this.isDwjPoint = "bottom-right";
      } else {
        this.isDwjPoint = "bottom-left";
      }
    },
    // 智能文字定位-偏移位置
    calcTextOffset(borderPoint) {
      //Message.warning(this.isDwjPoint+'--'+borderPoint.x)
      switch (this.isDwjPoint) {
        case "top-left":
          if (borderPoint.x < 100) {
            return 30;
          } else if (borderPoint.x < 110 && borderPoint.x >= 100) {
            return 25;
          } else {
            return 5;
          }
        case "top-right":
          // 以200为基准点进行计算
          // 默认返回15,borderPoint.x每增加10,返回值增加10
          return Math.max(5, 5 + (borderPoint.x - 200) / 10 * 10);
        case "bottom-right":
          return Math.max(5, 5 + (borderPoint.x - 200) / 10 * 10);
        case "bottom-left":
          if (borderPoint.x < 100) {
            return 30;
          } else if (borderPoint.x <= 110 && borderPoint.x >= 100) {
            return 25;
          } else {
            return 5;
          }
        default:
          return 10;
      }
    },
    // 撤销上一步绘图
    undoPreviousDrawing() {
      // 时间戳和增加的类型这里就用到了(๑¯㉨¯๑)
      // 合并两个集合按照特丁定的时间降序排列一下
      let rightList = this.pendingShapesRight;
      let leftsList = this.pendingShapesLefts;
      rightList = JSON.parse(JSON.stringify(rightList));
      leftsList = JSON.parse(JSON.stringify(leftsList));
      let zyEyeList = [...rightList, ...leftsList];
      zyEyeList.sort((a, b) => b.timestamp - a.timestamp);
      if (zyEyeList.length > 0) {
        let zyEye = zyEyeList[0].zyEye;
        let paramsCs = this.getEyeCorneaCs(zyEye);
        let { pendingShapesId } = paramsCs;
        if (this[pendingShapesId].length > 0) {
          this[pendingShapesId].splice(-1, 1);
          this.toReDrawingCanvas(zyEye);
        }
      }
    },
    // 将暂存的数据确定到历史
    // 不可删除-不可回退的数据
    // 确定后的数据可保存入库
    ensureShapesToHistory() {
      let hasList = [];
      let list = ["Right", "Lefts"];
      for (let i = 0; i < list.length; i++) {
        let zyEye = list[i];
        let paramsCs = this.getEyeCorneaCs(zyEye);
        let { pendingShapesId, drawingHistoryId } = paramsCs;
        if (this[pendingShapesId].length > 0) {
          this[drawingHistoryId] = this[drawingHistoryId].concat(this[pendingShapesId]);
          this[pendingShapesId] = [];
          let num = this.saveDrawingDataToCache(zyEye);
          hasList.push(num);
        }
      }
      if (hasList.includes("1")) {
        setTimeout(() => {
          Message.success("标注的 数据已暂存到缓存");
        });
      }
    },
    // 暂存绘制数据到本地缓存
    saveDrawingDataToCache(zyEye) {
      let paramsCs = this.getEyeCorneaCs(zyEye);
      let { drawingHistoryId, imageObjId } = paramsCs;
      if (this[drawingHistoryId].length > 0) {
        const data = {
          image: this[imageObjId] ? this[imageObjId].src : null,
          shapes: this[drawingHistoryId]
        };
        let zyEyeCorneaData = zyEye + "CorneaData";
        localStorage.setItem(zyEyeCorneaData, JSON.stringify(data));
        return "1";
      } else {
        return "0";
      }
    },
    // 清空画布再加载图片
    clearCanvasData() {
      let list = ["Right", "Lefts"];
      for (let i = 0; i < list.length; i++) {
        let zyEye = list[i];
        let paramsCs = this.getEyeCorneaCs(zyEye);
        let { ctxId, canvasId, drawingHistoryId, pendingShapesId, currentShapeId } = paramsCs;
        this[ctxId].clearRect(0, 0, this[canvasId].width, this[canvasId].height);
        this[drawingHistoryId] = [];
        this[pendingShapesId] = [];
        this[currentShapeId] = null;
        let zyEyeCorneaData = zyEye + "CorneaData";
        localStorage.removeItem(zyEyeCorneaData);
        this.loadingCtxImage(zyEye);
      }
      // 清空备用2隐藏图;整个画布无需加载画步
      for (let j = 0; j < list.length; j++) {
        let zyEye = list[j];
        let paramsCs = this.getEyeCorneaCs(zyEye, "print");
        let { ctxId, canvasId } = paramsCs;
        this[ctxId].clearRect(0, 0, this[canvasId].width, this[canvasId].height);
      }
    },
    // 加载绘制数据
    loadDrawingData() {
      let list = ["Right", "Lefts"];
      for (let i = 0; i < list.length; i++) {
        let savedData = null;
        let zyEye = list[i];
        let zyEyeCorneaData = zyEye + "CorneaData";
        let paramsCs = this.getEyeCorneaCs(zyEye);
        let { drawingHistoryId } = paramsCs;
        savedData = localStorage.getItem(zyEyeCorneaData);
        if (savedData) {
          const data = JSON.parse(savedData);
          this[drawingHistoryId] = data.shapes || [];
          this.toReDrawingCanvas(zyEye);
        }
      }
    },
    // 绘制四等分标线边界线-测试用
    drawQuadrantLinesByDwj(zyEye, print) {
      let is_enable = "dwj001";
      if (is_enable === "dwj002") {
        let paramsCs = this.getEyeCorneaCs(zyEye, print);
        let { canvasId, ctxId, imageRadiusId } = paramsCs;
 
        const centerX = this[canvasId].width / 2;
        const centerY = this[canvasId].height / 2;
 
        this[ctxId].strokeStyle = "#FF0000";
        this[ctxId].lineWidth = 1;
 
        // 水平中线
        this[ctxId].beginPath();
        this[ctxId].moveTo(0, centerY);
        this[ctxId].lineTo(this[canvasId].width, centerY);
        this[ctxId].stroke();
 
        // 垂直中线
        this[ctxId].beginPath();
        this[ctxId].moveTo(centerX, 0);
        this[ctxId].lineTo(centerX, this[canvasId].height);
        this[ctxId].stroke();
 
        // 绘制圆形边界
        let imageRadius = this[imageRadiusId] - 18;
        this[ctxId].beginPath();
        this[ctxId].arc(this[canvasId].x, this[canvasId].y, imageRadius, 0, Math.PI * 2);
        this[ctxId].strokeStyle = "#2d5afa"; //边界线颜色
        this[ctxId].lineWidth = 1;       //边界线宽度
        this[ctxId].stroke();
 
        // 使用贝塞尔曲线绘制椭圆的兼容方法
        this.drawEllipseBezierByDwj(zyEye, print)
      }
    },
    // 使用贝塞尔曲线绘制椭圆的兼容方法
    drawEllipseBezierByDwj(zyEye, print) {
      // 椭圆半径长和宽
      let radiusX = 100
      let radiusY = 60
 
      let paramsCs = this.getEyeCorneaCs(zyEye, print);
      let { ctxId, canvasId } = paramsCs;
 
      const canvasWidth = this[canvasId].width;
      const canvasHeight = this[canvasId].height;
 
      // 使用自定义半径或默认值
      const customRadiusX = radiusX || canvasWidth / 2;
      const customRadiusY = radiusY || canvasHeight / 2;
 
      const centerX = canvasWidth / 2;
      const centerY = canvasHeight / 2;
 
      // 保存当前绘图状态
      this[ctxId].save();
 
      // 开始绘制路径
      this[ctxId].beginPath();
 
      // 计算控制点偏移量
      const offsetX = customRadiusX * 0.5522848;
      const offsetY = customRadiusY * 0.5522848;
 
      // 计算关键点坐标
      const top = [centerX, centerY - customRadiusY];
      const right = [centerX + customRadiusX, centerY];
      const bottom = [centerX, centerY + customRadiusY];
      const left = [centerX - customRadiusX, centerY];
 
      // 移动到顶部点
      this[ctxId].moveTo(top[0], top[1]);
 
      // 绘制四条贝塞尔曲线形成椭圆
      this[ctxId].bezierCurveTo(
        top[0] + offsetX, top[1],
        right[0], right[1] - offsetY,
        right[0], right[1]
      );
 
      this[ctxId].bezierCurveTo(
        right[0], right[1] + offsetY,
        bottom[0] + offsetX, bottom[1],
        bottom[0], bottom[1]
      );
 
      this[ctxId].bezierCurveTo(
        bottom[0] - offsetX, bottom[1],
        left[0], left[1] + offsetY,
        left[0], left[1]
      );
 
      this[ctxId].bezierCurveTo(
        left[0], left[1] - offsetY,
        top[0] - offsetX, top[1],
        top[0], top[1]
      );
 
      // 设置椭圆样式
      this[ctxId].strokeStyle = "#000000";
      this[ctxId].lineWidth = 2;
 
      // 绘制椭圆边框
      this[ctxId].stroke();
 
      // 恢复绘图状态
      this[ctxId].restore();
    },
  }
};

使用canvas绘制椭圆,在椭圆上自由绘制并引入标注线和标注文字使用canvas绘制椭圆,在椭圆上自由绘制并引入标注线和标注文字

© 版权声明

相关文章

暂无评论

none
暂无评论...