/**
* @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();
},
}
};


© 版权声明
文章版权归作者所有,未经允许请勿转载。
相关文章
暂无评论...


