|
|
@@ -10,7 +10,7 @@
|
|
|
<!-- 请先制作模版 -->
|
|
|
</div>
|
|
|
<div v-if="showContextMenu" class="custom_context_menu" :style="{ top: contextMenuY + 'px', left: contextMenuX + 'px' }" @click="hideContextMenu">
|
|
|
- <div class="menu_item" @click="handleMenuAction('download')">图片另存为</div>
|
|
|
+ <div class="menu_item" @click="handleMenuAction('download')">图片另存为(放大后点另存可提高图片分率)</div>
|
|
|
<div class="menu_item" @click="handleMenuAction('fitScreen')">适合屏幕</div>
|
|
|
<div class="menu_item" @click="handleMenuAction('zoomIn')">放大(向上滚轮)</div>
|
|
|
<div class="menu_item" @click="handleMenuAction('zoomOut')">缩小(向下滚轮)</div>
|
|
|
@@ -55,7 +55,15 @@ export default {
|
|
|
type:Boolean,
|
|
|
default:false
|
|
|
},//是否异常处使用 区别 异常处理使用的地方 正常答案显示蓝色
|
|
|
-
|
|
|
+ usedCardType:{
|
|
|
+ type:Number,
|
|
|
+ default:2
|
|
|
+ },//默认三方卡 1 系统卡 2 三方卡
|
|
|
+
|
|
|
+ currentPage:{
|
|
|
+ type:Number,
|
|
|
+ default:1
|
|
|
+ },//当前页码 默认第一页
|
|
|
downLoadName:{
|
|
|
type:String,
|
|
|
default:''
|
|
|
@@ -63,6 +71,10 @@ export default {
|
|
|
imageIndex:{//图片索引
|
|
|
type:[String,Number],
|
|
|
default:''
|
|
|
+ },
|
|
|
+ scoreFontSize:{
|
|
|
+ type:Number,
|
|
|
+ default:50
|
|
|
}
|
|
|
},
|
|
|
computed:{
|
|
|
@@ -97,7 +109,10 @@ export default {
|
|
|
width:0,
|
|
|
height:0
|
|
|
},//画布的大小
|
|
|
-
|
|
|
+ imageInfo:{
|
|
|
+ width:0,
|
|
|
+ height:0
|
|
|
+ },//原始图片的大小
|
|
|
canvas:null,//画板canvas
|
|
|
ctx:null,//画板上下文
|
|
|
|
|
|
@@ -146,6 +161,8 @@ export default {
|
|
|
CacheHalfRight:new Image(),//缓存的半对图片
|
|
|
CacheTypicalError:new Image(),//缓存的典型错误图片
|
|
|
CacheExcellentAnswer:new Image(),//缓存的优秀答案图片
|
|
|
+ jHeight:0,//跨页的标注 需要减去的高度
|
|
|
+ blockList:[],//块列表
|
|
|
|
|
|
|
|
|
}
|
|
|
@@ -155,7 +172,12 @@ export default {
|
|
|
{
|
|
|
handler(newVal, oldVal)
|
|
|
{
|
|
|
- this.InitData();//初始化数据
|
|
|
+ console.log("地址变化了",this.paperImgUrl);
|
|
|
+ if(this.paperImgUrl)
|
|
|
+ {
|
|
|
+ this.InitData();//初始化数据
|
|
|
+ }
|
|
|
+
|
|
|
},
|
|
|
deep: true ,// 如果需要深度监听数组内部对象的变化
|
|
|
listener: true//立即执行一次
|
|
|
@@ -436,184 +458,104 @@ export default {
|
|
|
},
|
|
|
|
|
|
//图片加载完成后绘制图片
|
|
|
- drawImage() {
|
|
|
+ drawImage()
|
|
|
+ {
|
|
|
// if (this.image) {
|
|
|
this.canvas=this.$refs.paperCanvas;
|
|
|
let ctx = this.canvas.getContext('2d');
|
|
|
- // ctx.imageSmoothingEnabled = false;//禁用图片平滑
|
|
|
- // this.paperCtx.drawImage(this.image, 0, 0,this.canvasInfo.width,this.canvasInfo.height);
|
|
|
- // 根据 devicePixelRatio 缩放图片
|
|
|
- // ctx.drawImage(
|
|
|
- // this.image,
|
|
|
- // 0, 0,
|
|
|
- // this.image.width, this.image.height,
|
|
|
- // 0, 0,
|
|
|
- // this.canvasInfo.width, this.canvasInfo.height
|
|
|
- // );
|
|
|
ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
|
|
|
|
|
|
this.ImageInfoChange();//用image图片替代背景 是为了高清显示
|
|
|
|
|
|
console.log("加载边框数据",this.drawData);
|
|
|
- for(var i=0;i<this.drawData.length;i++)
|
|
|
+ this.DrawDataInfo();//加载边框数据
|
|
|
+ },
|
|
|
+
|
|
|
+
|
|
|
+ //绘制批注信息
|
|
|
+ DrawDataInfo()
|
|
|
+ {
|
|
|
+ let ctx = this.canvas.getContext('2d');
|
|
|
+ for(var i=0;i<this.drawData.length;i++)
|
|
|
{
|
|
|
let item=this.drawData[i];
|
|
|
- const point=JSON.parse(item.samplingPosition);
|
|
|
- var obj={
|
|
|
+ const point=JSON.parse(item.samplingPosition);//原始采分点的坐标
|
|
|
+
|
|
|
+ console.log("打印point",point);
|
|
|
+ console.log("打印卡类型",this.usedCardType);
|
|
|
+ let blockPoint='';//切块的坐标
|
|
|
+ let blockList=[];//跨页的后面的页的y坐标需要减去的高度
|
|
|
+ let jHeight=0;//跨页的标注 需要减去的高度
|
|
|
+ let obj={
|
|
|
x:point.x*this.zoomRate*this.scale,
|
|
|
y:point.y*this.zoomRate*this.scale,
|
|
|
- }
|
|
|
- //如果是批阅块的坐标 需要相加
|
|
|
- if(item.pagePaintingVOS)
|
|
|
- {
|
|
|
- console.log("打印item",item);
|
|
|
- // let pageItem = item.pagePaintingVOS.find(item => item.page == point.page);
|
|
|
- const pointIndex=point.index || 0;//默认0
|
|
|
- let pageItem = item.pagePaintingVOS[pointIndex];
|
|
|
- // item.pagePaintingVOS.forEach((item,index) => {
|
|
|
- // if(index==point.index && item.page == point.page)
|
|
|
- // {
|
|
|
- // pageItem=item;
|
|
|
- // }
|
|
|
- // });
|
|
|
- //需要同时根据索引和页面查找
|
|
|
- // const pageItem = item.pagePaintingVOS.find(item => item.page == point.page && item.index == point.index);
|
|
|
- console.log("打印pageItem",pageItem);
|
|
|
+ };//采分点的坐标
|
|
|
|
|
|
- if (pageItem) {
|
|
|
- obj.x = (pageItem.x + point.x) * this.zoomRate * this.scale;
|
|
|
- obj.y = (pageItem.y + point.y) * this.zoomRate * this.scale;
|
|
|
+ if(this.usedCardType==1)
|
|
|
+ {
|
|
|
+ // 如果是系统卡需要特殊处理 需要将坐标转成系统卡的坐标 并且需要去掉上下左右的边框
|
|
|
+ console.log("打印this.paperImgInfo",this.paperImgInfo);
|
|
|
+ console.log("如果是系统卡需要特殊处理",item);
|
|
|
+ let templateInfo={
|
|
|
+ width:794-30*2,//减去左右的边距
|
|
|
+ height:1123-25*2//减去上下的边距
|
|
|
+ };//模板去掉边框的尺寸
|
|
|
+ //如果长大于宽 就是A3 否则就是A4
|
|
|
+ if(this.paperImgInfo.width>this.paperImgInfo.height)
|
|
|
+ {
|
|
|
+ //A3 1588*1123
|
|
|
+ templateInfo={
|
|
|
+ width:1588-30*2,//减去左右的边距
|
|
|
+ height:1123-25*2//减去上下的边距
|
|
|
+ };//模板去掉边框的尺寸
|
|
|
}
|
|
|
- console.log("打印计算后的obj",obj);
|
|
|
- }
|
|
|
- // 绘制文字 定位去和客观题组不用显示
|
|
|
-
|
|
|
- // console.log("打印标题",item.questionName);
|
|
|
- // ctx.fillStyle = 'red';
|
|
|
- ctx.fillStyle = '#D81E06';
|
|
|
- ctx.textAlign = 'center';
|
|
|
- ctx.textBaseline = 'middle';
|
|
|
- if(item.questionName=='总分')
|
|
|
+ let imagePoint={};
|
|
|
+ //客观题 需要减去 30 和25 因为客观题的坐标是相当于试卷原点 其他的主观题坐标是相当于批阅块的
|
|
|
+ if(item.titleType==1)
|
|
|
{
|
|
|
- const fontSize = Math.max(12, 50 * this.scale); // 最小字体12px,基础字体16px
|
|
|
- ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
|
|
|
-
|
|
|
- ctx.textAlign = 'left';
|
|
|
-
|
|
|
- const iconX=obj.x-20*this.zoomRate*this.scale;
|
|
|
- const iconY=obj.y-20*this.zoomRate*this.scale;
|
|
|
- const iconWidth = 100*this.zoomRate*this.scale;
|
|
|
- const iconHeight = 100*this.zoomRate*this.scale;
|
|
|
-
|
|
|
- // displayType:res.data.displayType,//显示类型 0-分数 1-对错 2-等级
|
|
|
- // displayName: res.data.displayName,//显示值
|
|
|
- // correctType: res.data.correctType,//显示对错的时候 0-错 1-半对 2-全对
|
|
|
- if(item.displayType === 0 || item.displayType === 2){
|
|
|
- ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
- }else{
|
|
|
- if(item.correctType==0){
|
|
|
- //0 分全错
|
|
|
- ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
|
|
|
- }else if(item.correctType==2){
|
|
|
- //满分 全对
|
|
|
- ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- }else{
|
|
|
- //半对
|
|
|
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- }
|
|
|
- }
|
|
|
+ imagePoint={
|
|
|
+ x:((point.x-30)/templateInfo.width)*this.paperImgInfo.width,
|
|
|
+ y:((point.y-15)/templateInfo.height)*this.paperImgInfo.height,
|
|
|
+ };//相对于原图试卷的坐标 这里减去30是 黑块相对于左边的边距30px 上边的边距25px 减去15 是因为选择题的采分点 使用的是第一个答案的初始坐标点 需要减去答案的高度使其上下居中
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- const fontSize = Math.max(12, 24 * this.scale); // 最小字体12px,基础字体16px
|
|
|
- // ctx.font = '30px Arial';
|
|
|
-
|
|
|
- ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
|
|
|
-
|
|
|
- ctx.textAlign = 'left';
|
|
|
- //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
|
|
|
- const iconX=obj.x-20*this.zoomRate*this.scale;
|
|
|
- const iconY=obj.y-20*this.zoomRate*this.scale;
|
|
|
- const iconWidth = 50*this.zoomRate*this.scale;
|
|
|
- const iconHeight = 50*this.zoomRate*this.scale;
|
|
|
- // console.log("打印item.score",item.score)
|
|
|
- if(item.displayType === 0 || item.displayType === 2){
|
|
|
- ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
- }else{
|
|
|
- if(item.correctType==0){
|
|
|
- //0 分全错
|
|
|
- ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
|
|
|
- }else if(item.correctType==2){
|
|
|
- //满分 全对
|
|
|
- ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- }else{
|
|
|
- //半对
|
|
|
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- }
|
|
|
- }
|
|
|
- // if(item.score==0)
|
|
|
- // {
|
|
|
-
|
|
|
-
|
|
|
- // //0 分全错
|
|
|
- // ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
|
|
|
-
|
|
|
- // }
|
|
|
- // else if(item.score==item.fullScore)
|
|
|
- // {
|
|
|
- // //满分 全对
|
|
|
- // ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- // }
|
|
|
- // else
|
|
|
- // {
|
|
|
- // //半对
|
|
|
- // ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- // }
|
|
|
+ imagePoint={
|
|
|
+ x:(point.x/templateInfo.width)*this.paperImgInfo.width ,
|
|
|
+ y:(point.y/templateInfo.height)*this.paperImgInfo.height,
|
|
|
+ };//相对于原图试卷的坐标
|
|
|
}
|
|
|
- // ctx.fillText(`${item.score}`,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
|
|
|
- // ctx.fillStyle = 'blue';
|
|
|
- // ctx.font = `24px Arial`; // 让文字大小跟随缩放
|
|
|
- // ctx.textAlign = 'center';
|
|
|
- // ctx.textBaseline = 'middle';
|
|
|
- // ctx.fillText(item.questionName,obj.x-65*this.zoomRate*this.scale,obj.y);
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- // ctx.restore();
|
|
|
- // }
|
|
|
- },
|
|
|
-
|
|
|
- //下载图片绘制
|
|
|
- DownloadDrawImage()
|
|
|
- {
|
|
|
- this.canvas=this.$refs.paperCanvas;
|
|
|
- let ctx = this.canvas.getContext('2d');
|
|
|
-
|
|
|
- ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
|
|
|
- ctx.drawImage(this.image, 0, 0,this.canvasInfo.width,this.canvasInfo.height);
|
|
|
+ // console.log("系统卡相对于原图试卷的坐标imagePoint",imagePoint);
|
|
|
+ // let offsetX=this.GetInteger(imagePoint.x*this.zoomRate*this.scale);
|
|
|
+ // console.log("系统卡转换的采分点坐标offsetX",offsetX);
|
|
|
+ // let offsetY=Number(imagePoint.y*this.zoomRate*this.scale);
|
|
|
+ // console.log("系统卡转换的采分点坐标offsetY",offsetY);
|
|
|
+ obj={
|
|
|
+ x:imagePoint.x*this.zoomRate*this.scale,
|
|
|
+ y:imagePoint.y*this.zoomRate*this.scale,
|
|
|
+ };//采分点坐标更新
|
|
|
+
|
|
|
|
|
|
-
|
|
|
- // console.log("加载边框数据",this.drawData);
|
|
|
- for(var i=0;i<this.drawData.length;i++)
|
|
|
- {
|
|
|
- let item=this.drawData[i];
|
|
|
- const point=JSON.parse(item.samplingPosition);
|
|
|
- var obj={
|
|
|
- x:point.x*this.zoomRate*this.scale,
|
|
|
- y:point.y*this.zoomRate*this.scale,
|
|
|
+
|
|
|
}
|
|
|
+ console.log("打印当前题目",item.questionName);
|
|
|
+ console.log("打印转换前采分点坐标point",point);
|
|
|
+ console.log("打印转换后相对批阅块的采分点坐标obj",obj);
|
|
|
//如果是批阅块的坐标 需要相加
|
|
|
+ console.log("打印item",item);
|
|
|
if(item.pagePaintingVOS)
|
|
|
{
|
|
|
console.log("打印item",item);
|
|
|
// let pageItem = item.pagePaintingVOS.find(item => item.page == point.page);
|
|
|
const pointIndex=point.index || 0;//默认0
|
|
|
- let pageItem = item.pagePaintingVOS[pointIndex];
|
|
|
+ blockPoint = item.pagePaintingVOS[pointIndex];
|
|
|
+ const pointPage=point.page;//采分点所在的页码
|
|
|
+ if(item.pagePaintingVOS.length>1)
|
|
|
+ {
|
|
|
+ //跨页的
|
|
|
+ blockList=item.pagePaintingVOS || [];
|
|
|
+ }
|
|
|
// item.pagePaintingVOS.forEach((item,index) => {
|
|
|
// if(index==point.index && item.page == point.page)
|
|
|
// {
|
|
|
@@ -622,42 +564,122 @@ export default {
|
|
|
// });
|
|
|
//需要同时根据索引和页面查找
|
|
|
// const pageItem = item.pagePaintingVOS.find(item => item.page == point.page && item.index == point.index);
|
|
|
- console.log("打印pageItem",pageItem);
|
|
|
+ console.log("打印blockPoint",blockPoint);
|
|
|
+ let newBlockPoint=blockPoint;
|
|
|
+ //如果是系统卡需要特殊处理 需要将坐标转成系统卡的坐标 并且需要去掉上下左右的边框
|
|
|
+ if(this.usedCardType==1)
|
|
|
+ {
|
|
|
+
|
|
|
+ let templateInfo={
|
|
|
+ width:794-30*2,//减去左右的边距
|
|
|
+ height:1123-25*2//减去上下的边距
|
|
|
+ };//模板去掉边框的尺寸
|
|
|
+ //如果长大于宽 就是A3 否则就是A4
|
|
|
+ if(this.paperImgInfo.width>this.paperImgInfo.height)
|
|
|
+ {
|
|
|
+ //A3 1588*1123
|
|
|
+ templateInfo={
|
|
|
+ width:1588-30*2,//减去左右的边距
|
|
|
+ height:1123-25*2//减去上下的边距
|
|
|
+ };//模板去掉边框的尺寸
|
|
|
+ }
|
|
|
+ newBlockPoint={
|
|
|
+ x:this.GetInteger(((blockPoint.x-30)/templateInfo.width)*this.paperImgInfo.width),
|
|
|
+ y:this.GetInteger(((blockPoint.y-25)/templateInfo.height)*this.paperImgInfo.height),
|
|
|
+ w:this.GetInteger((blockPoint.w/templateInfo.width)*this.paperImgInfo.width),
|
|
|
+ h:this.GetInteger((blockPoint.h/templateInfo.height)*this.paperImgInfo.height),
|
|
|
+ page:blockPoint.page,
|
|
|
+ };//相对于原图试卷的坐标
|
|
|
+ blockPoint=newBlockPoint;
|
|
|
+ if(item.pagePaintingVOS.length>1)
|
|
|
+ {
|
|
|
+ blockList=[];
|
|
|
+ for(var j=0;j<item.pagePaintingVOS.length;j++)
|
|
|
+ {
|
|
|
+ let blockObj=item.pagePaintingVOS[j];
|
|
|
+ let obj={
|
|
|
+ x:this.GetInteger(((blockObj.x-30)/templateInfo.width)*this.paperImgInfo.width),
|
|
|
+ y:this.GetInteger(((blockObj.y-25)/templateInfo.height)*this.paperImgInfo.height),
|
|
|
+ w:this.GetInteger((blockObj.w/templateInfo.width)*this.paperImgInfo.width),
|
|
|
+ h:this.GetInteger((blockObj.h/templateInfo.height)*this.paperImgInfo.height),
|
|
|
+ page:blockObj.page,
|
|
|
+ };
|
|
|
+
|
|
|
+ blockList.push(obj);
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- if (pageItem) {
|
|
|
- obj.x = (pageItem.x + point.x) * this.zoomRate * this.scale;
|
|
|
- obj.y = (pageItem.y + point.y) * this.zoomRate * this.scale;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if(pointPage != this.pointPage)
|
|
|
+ {
|
|
|
+ //如果不是同一页
|
|
|
+ console.log("打印不同页的坐标 打印第一页的切块坐标",newBlockPoint);
|
|
|
+ jHeight=newBlockPoint.h;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (blockPoint) {
|
|
|
+ obj.x =this.GetInteger(newBlockPoint.x* this.zoomRate * this.scale+ obj.x);
|
|
|
+ obj.y =this.GetInteger(newBlockPoint.y* this.zoomRate * this.scale +obj.y);
|
|
|
}
|
|
|
console.log("打印计算后的obj",obj);
|
|
|
}
|
|
|
+
|
|
|
+ console.log("打印转换后相对于原试卷的采分点坐标obj",obj);
|
|
|
// 绘制文字 定位去和客观题组不用显示
|
|
|
|
|
|
- // console.log("打印标题",item.questionName);
|
|
|
- // ctx.fillStyle = 'red';
|
|
|
- ctx.fillStyle = '#D81E06';
|
|
|
- ctx.textAlign = 'center';
|
|
|
- ctx.textBaseline = 'middle';
|
|
|
+ //console.log("打印标题",item.questionName);
|
|
|
+ //ctx.fillStyle = 'red';
|
|
|
+ ctx.fillStyle = '#D81E06';
|
|
|
+ ctx.textAlign = 'center';
|
|
|
+ ctx.textBaseline = 'middle';
|
|
|
if(item.questionName=='总分')
|
|
|
{
|
|
|
- const fontSize = Math.max(12, 50 * this.scale); // 最小字体12px,基础字体16px
|
|
|
+ const fontSize = Math.max(12, this.scoreFontSize * this.scale); // 最小字体12px,基础字体50px
|
|
|
ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
|
|
|
|
|
|
ctx.textAlign = 'left';
|
|
|
-
|
|
|
- const iconX=obj.x-20*this.zoomRate*this.scale;
|
|
|
- const iconY=obj.y-20*this.zoomRate*this.scale;
|
|
|
- const iconWidth = 100*this.zoomRate*this.scale;
|
|
|
- const iconHeight = 100*this.zoomRate*this.scale;
|
|
|
-
|
|
|
-
|
|
|
- if(item.displayType == 0 || item.displayType === 2){
|
|
|
- ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
+ // 添加下划线
|
|
|
+ let text = '',textWidth = 0;
|
|
|
+ if(item.displayType === 0 || item.displayType === 2){
|
|
|
+ text = item.displayName.toString();
|
|
|
+ textWidth = ctx.measureText(text).width;
|
|
|
}else{
|
|
|
+ textWidth = 2 * fontSize*this.zoomRate*this.scale; ;
|
|
|
+ }
|
|
|
+ const underlineY = obj.y + 50*this.zoomRate * this.scale ; // 可根据需要调整下划线位置
|
|
|
+ const startX = obj.x +35*this.zoomRate*this.scale;
|
|
|
+
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(startX, underlineY);
|
|
|
+ ctx.lineTo(startX + textWidth, underlineY);
|
|
|
+ ctx.strokeStyle = ctx.fillStyle; // 使用与文字相同的颜色
|
|
|
+ ctx.lineWidth = 4;
|
|
|
+ ctx.stroke();
|
|
|
+ // 添加下划线2
|
|
|
+
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(startX-20, underlineY+20*this.zoomRate*this.scale);
|
|
|
+ ctx.lineTo(startX + textWidth + 20, underlineY+20*this.zoomRate*this.scale);
|
|
|
+ ctx.strokeStyle = ctx.fillStyle; // 使用与文字相同的颜色
|
|
|
+ ctx.lineWidth = 4;
|
|
|
+ ctx.stroke();
|
|
|
+ if(item.displayType === 0 || item.displayType === 2){
|
|
|
+ ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
+ }else{
|
|
|
+ //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
|
|
|
+ const iconX=obj.x +35*this.zoomRate*this.scale;
|
|
|
+ const iconY=obj.y-fontSize*this.zoomRate*this.scale;
|
|
|
+ const iconWidth = 2 * fontSize*this.zoomRate*this.scale;
|
|
|
+ const iconHeight = 2 * fontSize*this.zoomRate*this.scale;
|
|
|
if(item.correctType==0){
|
|
|
//0 分全错
|
|
|
ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
|
|
|
}else if(item.correctType==2){
|
|
|
- //满分 全对
|
|
|
+ //满分全对
|
|
|
ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
}else{
|
|
|
//半对
|
|
|
@@ -667,20 +689,21 @@ export default {
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- const fontSize = Math.max(12, 24 * this.scale); // 最小字体12px,基础字体16px
|
|
|
+ const fontSize = Math.max(12, 18 * this.scale); // 最小字体12px,基础字体18px
|
|
|
// ctx.font = '30px Arial';
|
|
|
-
|
|
|
ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
|
|
|
-
|
|
|
ctx.textAlign = 'left';
|
|
|
//判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
|
|
|
const iconX=obj.x-20*this.zoomRate*this.scale;
|
|
|
const iconY=obj.y-20*this.zoomRate*this.scale;
|
|
|
- const iconWidth = 50*this.zoomRate*this.scale;
|
|
|
- const iconHeight = 50*this.zoomRate*this.scale;
|
|
|
-
|
|
|
- if(item.displayType === 0 || item.displayType === 2){
|
|
|
- ctx.fillText(`${item.displayName}`,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
+ const iconWidth = 40*this.zoomRate*this.scale;
|
|
|
+ const iconHeight = 40*this.zoomRate*this.scale;
|
|
|
+ // console.log("打印item.score",item.score)
|
|
|
+ // displayType:res.data.displayType,//显示类型 0-分数 1-对错 2-等级
|
|
|
+ // displayName: res.data.displayName,//显示值
|
|
|
+ // correctType: res.data.correctType,//显示对错的时候 0-错 1-半对 2-全对
|
|
|
+ if(item.displayType === 2){
|
|
|
+ ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
}else{
|
|
|
if(item.correctType==0){
|
|
|
//0 分全错
|
|
|
@@ -692,36 +715,171 @@ export default {
|
|
|
//半对
|
|
|
ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
}
|
|
|
+ if(item.displayType === 0){//0-分数 显示分数和对错
|
|
|
+ ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
+ }
|
|
|
}
|
|
|
- // console.log("打印item.score",item.score)
|
|
|
- // if(item.score==0)
|
|
|
- // {
|
|
|
-
|
|
|
-
|
|
|
- // //0 分全错
|
|
|
- // ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
|
|
|
-
|
|
|
- // }
|
|
|
- // else if(item.score==item.fullScore)
|
|
|
- // {
|
|
|
- // //满分 全对
|
|
|
- // ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- // }
|
|
|
- // else
|
|
|
- // {
|
|
|
- // //半对
|
|
|
- // ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
|
|
|
- // }
|
|
|
}
|
|
|
- // ctx.fillText(item.score,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
-
|
|
|
+ // ctx.fillText(item.displayName,obj.x+35*this.zoomRate*this.scale,obj.y);
|
|
|
// ctx.fillStyle = 'blue';
|
|
|
// ctx.font = `24px Arial`; // 让文字大小跟随缩放
|
|
|
// ctx.textAlign = 'center';
|
|
|
// ctx.textBaseline = 'middle';
|
|
|
// ctx.fillText(item.questionName,obj.x-65*this.zoomRate*this.scale,obj.y);
|
|
|
+ //绘制标注信息
|
|
|
+ if(item.drawLineData)
|
|
|
+ {
|
|
|
+ //有标注信息 加载标注 所有的坐标都要加上批阅块的初始坐标
|
|
|
+ console.log("打印point",point);
|
|
|
+
|
|
|
+ console.log("打印当前的页面",this.currentPage);
|
|
|
+ console.log("打印当前的批阅块数组",blockList);
|
|
|
+ const drawLineData=JSON.parse(item.drawLineData);
|
|
|
+ console.log("打印drawLineData",drawLineData);
|
|
|
|
|
|
|
|
|
+ // for(var j=0;j<drawLineData.length;j++)
|
|
|
+ // {
|
|
|
+ // var drawItem=drawLineData[j];
|
|
|
+
|
|
|
+ // console.log("打印drawItem",drawItem);
|
|
|
+ // // 扣分点 加分点 标记// 1:文字 (扣分留痕 显示扣分信息) 2:划线 3:波浪线 4:画笔 5:评语
|
|
|
+ // if(drawItem.drawType==1)
|
|
|
+ // {
|
|
|
+
|
|
|
+ // const fontSize = Math.max(12, 40 * this.zoomRate* this.scale); // 最小字体12px,基础字体16px
|
|
|
+ // ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
|
|
|
+ // // ctx.font = '30px Arial';
|
|
|
+ // ctx.fillStyle = '#D81E06';
|
|
|
+ // ctx.textAlign = 'center';
|
|
|
+ // ctx.textBaseline = 'middle';
|
|
|
+ // if(drawItem.type=='reduce')
|
|
|
+ // {
|
|
|
+ // ctx.fillText('-'+drawItem.score,(drawItem.x + blockPoint.x) * this.zoomRate * this.scale, (drawItem.y + blockPoint.y) * this.zoomRate * this.scale);
|
|
|
+ // }
|
|
|
+ // if(drawItem.type=='bonus')
|
|
|
+ // {
|
|
|
+ // ctx.fillText('+'+drawItem.score, (drawItem.x + blockPoint.x) * this.zoomRate * this.scale, (drawItem.y + blockPoint.y) * this.zoomRate * this.scale);
|
|
|
+ // }
|
|
|
+
|
|
|
+ // }
|
|
|
+ // else if(drawItem.drawType==2)
|
|
|
+ // {
|
|
|
+ // //绘制横线
|
|
|
+ // console.log("打印需要减去的高度",jHeight);
|
|
|
+ // jHeight=0;
|
|
|
+ // console.log("打印blockList",blockList);
|
|
|
+ // let drawX=this.GetInteger((drawItem.x+ blockPoint.x)* this.zoomRate * this.scale);
|
|
|
+ // let drawY=this.GetInteger((drawItem.y+blockPoint.y - jHeight)* this.zoomRate * this.scale);
|
|
|
+ // let drawEndX=this.GetInteger((drawItem.endX+ blockPoint.x)* this.zoomRate * this.scale);
|
|
|
+ // let drawEndY=this.GetInteger((drawItem.endY+blockPoint.y - jHeight)* this.zoomRate * this.scale);
|
|
|
+ // this.DrawHorizontalLine(drawX,drawY,drawEndX,drawEndY);
|
|
|
+ // // this.DrawHorizontalLine((drawItem.x+ blockPoint.x)* this.zoomRate * this.scale, (drawItem.y+blockPoint.y)* this.zoomRate * this.scale,(drawItem.endX+ blockPoint.x)* this.zoomRate * this.scale, (drawItem.endY+blockPoint.y)* this.zoomRate * this.scale);
|
|
|
+
|
|
|
+ // }
|
|
|
+ // else if(drawItem.drawType==3)
|
|
|
+ // {
|
|
|
+ // //绘制波浪线
|
|
|
+ // let startX=parseFloat(((drawItem.x + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ // let startY=parseFloat(((drawItem.y + blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ // let endX=parseFloat(((drawItem.endX + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ // let endY=parseFloat(((drawItem.endY +blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+
|
|
|
+ // this.DrawWaveLine(startX, startY,endX, endY);
|
|
|
+ // }
|
|
|
+ // else if(drawItem.drawType==4)
|
|
|
+ // {
|
|
|
+ // //绘制画笔数据
|
|
|
+ // // console.log("打印画笔数据",drawItem);
|
|
|
+ // this.DrawPenLine(drawItem,blockPoint);
|
|
|
+ // }
|
|
|
+ // else if(drawItem.drawType==5)
|
|
|
+ // {
|
|
|
+ // //绘制评语
|
|
|
+ // let startX=parseFloat(((drawItem.x + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ // let startY=parseFloat(((drawItem.y + blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ // // console.log("打印绘制评语数据",drawItem);
|
|
|
+ // this.DrawText(startX,startY,drawItem.text);
|
|
|
+ // }
|
|
|
+ // }
|
|
|
+
|
|
|
+ for(const [index, drawItem] of drawLineData.entries()) {
|
|
|
+ console.log("打印drawItem",drawItem);
|
|
|
+ // 计算通用的缩放因子,避免重复计算
|
|
|
+ const zoomScale = this.zoomRate * this.scale;
|
|
|
+ const offsetX = blockPoint.x * zoomScale;
|
|
|
+ const offsetY = blockPoint.y * zoomScale;
|
|
|
+
|
|
|
+ // 扣分点 加分点 标记// 1:文字 (扣分留痕 显示扣分信息) 2:划线 3:波浪线 4:画笔 5:评语
|
|
|
+ switch(drawItem.drawType) {
|
|
|
+ case 1: {
|
|
|
+ // 文字类型(扣分点/加分点标记)
|
|
|
+ const fontSize = Math.max(12, 40 * zoomScale);
|
|
|
+ ctx.font = `${fontSize}px Arial`;
|
|
|
+ ctx.fillStyle = '#D81E06';
|
|
|
+ ctx.textAlign = 'center';
|
|
|
+ ctx.textBaseline = 'middle';
|
|
|
+
|
|
|
+ const x = drawItem.x * zoomScale + offsetX;
|
|
|
+ const y = drawItem.y * zoomScale + offsetY;
|
|
|
+
|
|
|
+ if(drawItem.type==='reduce') {
|
|
|
+ ctx.fillText('-'+drawItem.score, x, y);
|
|
|
+ } else if(drawItem.type==='bonus') {
|
|
|
+ ctx.fillText('+'+drawItem.score, x, y);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 2: {
|
|
|
+ // 绘制横线
|
|
|
+ console.log("打印需要减去的高度",jHeight);
|
|
|
+ jHeight=0;
|
|
|
+ console.log("打印blockList",blockList);
|
|
|
+ const coords = {
|
|
|
+ x: this.GetInteger(drawItem.x * zoomScale + offsetX),
|
|
|
+ y: this.GetInteger(drawItem.y * zoomScale + offsetY - jHeight * zoomScale),
|
|
|
+ endX: this.GetInteger(drawItem.endX * zoomScale + offsetX),
|
|
|
+ endY: this.GetInteger(drawItem.endY * zoomScale + offsetY - jHeight * zoomScale)
|
|
|
+ };
|
|
|
+ this.DrawHorizontalLine(coords.x, coords.y, coords.endX, coords.endY);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 3: {
|
|
|
+ // 绘制波浪线
|
|
|
+ const coords = {
|
|
|
+ startX: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
|
|
|
+ startY: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2)),
|
|
|
+ endX: parseFloat((drawItem.endX * zoomScale + offsetX).toFixed(2)),
|
|
|
+ endY: parseFloat((drawItem.endY * zoomScale + offsetY).toFixed(2))
|
|
|
+ };
|
|
|
+ this.DrawWaveLine(coords.startX, coords.startY, coords.endX, coords.endY);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ case 4:
|
|
|
+ // 绘制画笔数据
|
|
|
+ this.DrawPenLine(drawItem,blockPoint);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 5: {
|
|
|
+ // 绘制评语
|
|
|
+ const coords = {
|
|
|
+ x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
|
|
|
+ y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
|
|
|
+ };
|
|
|
+ this.DrawText(coords.x, coords.y, drawItem.text);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ default:
|
|
|
+ console.warn('未知的绘图类型:', drawItem.drawType);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
|
|
|
|
|
|
@@ -729,67 +887,146 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- //加载答案框数据
|
|
|
- drawQuestionPosition()
|
|
|
+ //转成整数
|
|
|
+ GetInteger(value)
|
|
|
{
|
|
|
+ // 如果值为空、undefined 或 null,返回 0
|
|
|
+ if (value === null || value === undefined || value === '') {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果已经是数字,直接处理
|
|
|
+ if (typeof value === 'number') {
|
|
|
+ // 检查是否为 NaN
|
|
|
+ if (isNaN(value)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ // 使用 Math.round 四舍五入取整
|
|
|
+ return Math.round(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果是字符串,先尝试转换为数字
|
|
|
+ if (typeof value === 'string') {
|
|
|
+ // 去除首尾空格
|
|
|
+ value = value.trim();
|
|
|
+ // 如果是空字符串,返回 0
|
|
|
+ if (value === '') {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ // 转换为数字
|
|
|
+ const num = Number(value);
|
|
|
+ // 检查是否为有效数字
|
|
|
+ if (isNaN(num)) {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ // 四舍五入取整
|
|
|
+ return Math.round(num);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 其他情况,尝试转换为数字后取整
|
|
|
+ const num = Number(value);
|
|
|
+ return isNaN(num) ? 0 : Math.round(num);
|
|
|
+ },
|
|
|
|
|
|
- let canvas=this.$refs.paperCanvas;
|
|
|
- let ctx = canvas.getContext('2d');
|
|
|
- console.log("加载答案边框数据",this.questionPositionData);
|
|
|
- for(var i=0;i<this.questionPositionData.length;i++)
|
|
|
+ //画横线
|
|
|
+ DrawHorizontalLine(x1,y1,x2,y2)
|
|
|
+ {
|
|
|
+ console.log("画横线起始坐标点",x1, y1, x2, y2);
|
|
|
+ const canvas = this.$refs.paperCanvas;
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ ctx.strokeStyle = 'red';//设置红色
|
|
|
+ ctx.lineWidth = 2;//线条宽度
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(x1, y1);
|
|
|
+ ctx.lineTo(x2, y2);
|
|
|
+ ctx.stroke();
|
|
|
+ },
|
|
|
+ //画波浪线
|
|
|
+ DrawWaveLine(startX, startY, endX, endY)
|
|
|
+ {
|
|
|
+ // console.log("画波浪线起始坐标点",startX, startY, endX, endY);
|
|
|
+ const amplitude = 2; // 波浪的宽度
|
|
|
+ const frequency = 0.8; //振幅 越大越密集
|
|
|
+ //计算中间点
|
|
|
+ const dx=endX-startX;
|
|
|
+ const dy=endY-startY;
|
|
|
+
|
|
|
+
|
|
|
+ // 开始绘制
|
|
|
+ const canvas = this.$refs.paperCanvas;
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ ctx.strokeStyle = 'red';//设置红色
|
|
|
+ ctx.lineWidth = 2;//线条宽度
|
|
|
+ // 清除之前的线条
|
|
|
+ // ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);
|
|
|
+ ctx.beginPath();
|
|
|
+ ctx.moveTo(startX, startY);//绘制第一个点
|
|
|
+ //绘制波浪
|
|
|
+ // 绘制波浪线
|
|
|
+ for (let x = startX; x <= endX; x += 1) {
|
|
|
+ const y = startY + dy * (x - startX) / dx + amplitude * Math.sin(frequency * (x - startX));
|
|
|
+ ctx.lineTo(x, y);
|
|
|
+ }
|
|
|
+ // ctx.lineTo(endX, endY);//绘制最后一个点
|
|
|
+ // ctx.lineWidth = 2; // 设置线条宽度
|
|
|
+ ctx.stroke();
|
|
|
+ },
|
|
|
+
|
|
|
+ //绘制画笔数据
|
|
|
+ DrawPenLine(data,blockPoint)
|
|
|
{
|
|
|
- var item=this.questionPositionData[i];
|
|
|
-
|
|
|
- // var obj={
|
|
|
- // x:item.x*this.zoomRate*this.scale,
|
|
|
- // y:item.y*this.zoomRate*this.scale,
|
|
|
- // width:item.w*this.zoomRate*this.scale,
|
|
|
- // height:item.h*this.zoomRate*this.scale,
|
|
|
- // blockName:item.blockName,
|
|
|
- // // page:'',
|
|
|
- // // blockArea:'',
|
|
|
- // }
|
|
|
- // //外边框数据
|
|
|
- // if(item.unit=='mm')
|
|
|
- // {
|
|
|
- // obj={
|
|
|
- // x:mmToPx(item.x)*this.zoomRate*this.scale,
|
|
|
- // y:mmToPx(item.y)*this.zoomRate*this.scale,
|
|
|
- // width:mmToPx(item.w)*this.zoomRate*this.scale,
|
|
|
- // height:mmToPx(item.h)*this.zoomRate*this.scale,
|
|
|
- // blockName:item.blockName,
|
|
|
- // // page:item.page,
|
|
|
- // // blockArea:item.blockArea,
|
|
|
- // }
|
|
|
- // }
|
|
|
|
|
|
- for(var j=0;j<item.questionlist.length;j++)
|
|
|
+ let linelist=data.drawlineData;
|
|
|
+ if(linelist.length>0)
|
|
|
{
|
|
|
- for(var k=0;k<item.questionlist[j].answerList.length;k++)
|
|
|
- {
|
|
|
- var obj={
|
|
|
- x:mmToPx(item.questionlist[j].answerList[k].x)*this.zoomRate*this.scale,
|
|
|
- y:mmToPx(item.questionlist[j].answerList[k].y)*this.zoomRate*this.scale,
|
|
|
- width:mmToPx(item.questionlist[j].answerList[k].w)*this.zoomRate*this.scale,
|
|
|
- height:mmToPx(item.questionlist[j].answerList[k].h)*this.zoomRate*this.scale,
|
|
|
- // blockName:item.blockName,
|
|
|
+ const canvas = this.$refs.paperCanvas;
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ ctx.strokeStyle = 'red';//设置红色
|
|
|
+ ctx.lineWidth = 2;//线条宽度
|
|
|
+ // 开始绘制
|
|
|
+ ctx.beginPath();
|
|
|
+
|
|
|
+ // 绘制路径
|
|
|
+ for (let i = 0; i < linelist.length; i++) {
|
|
|
+ if(blockPoint)
|
|
|
+ {
|
|
|
+ let x=parseFloat(((linelist[i].x + blockPoint.x)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ let y=parseFloat(((linelist[i].y + blockPoint.y)* this.zoomRate * this.scale).toFixed(2));
|
|
|
+ ctx.lineTo(x, y);
|
|
|
}
|
|
|
- ctx.strokeRect(obj.x,obj.y,obj.width,obj.height);
|
|
|
+
|
|
|
}
|
|
|
+ ctx.stroke();
|
|
|
+ ctx.closePath();
|
|
|
}
|
|
|
-
|
|
|
- // ctx.font = '15px Arial';
|
|
|
-
|
|
|
- // ctx.textAlign = 'left';
|
|
|
- // // ctx.textBaseline = 'middle';
|
|
|
- // // 绘制文字
|
|
|
- // if(obj.blockArea!=2)
|
|
|
- // {
|
|
|
- // ctx.fillText(obj.blockName,obj.x, obj.y+15);
|
|
|
- // }
|
|
|
+ },
|
|
|
+
|
|
|
+ //绘制文字
|
|
|
+ DrawText(startX, startY, text)
|
|
|
+ {
|
|
|
+ // 开始绘制
|
|
|
+ const canvas = this.$refs.paperCanvas;
|
|
|
+ const ctx = canvas.getContext('2d');
|
|
|
+ // 设置字体样式
|
|
|
+ ctx.font = '15px Arial';
|
|
|
+ ctx.fillStyle = 'red';
|
|
|
+ ctx.textAlign = 'left';
|
|
|
+ // ctx.textBaseline = 'middle';
|
|
|
+ // 绘制文字
|
|
|
+ ctx.fillText(text,startX, startY);
|
|
|
+ },
|
|
|
+
|
|
|
+ //下载图片绘制
|
|
|
+ DownloadDrawImage()
|
|
|
+ {
|
|
|
+ this.canvas=this.$refs.paperCanvas;
|
|
|
+ let ctx = this.canvas.getContext('2d');
|
|
|
|
|
|
- }
|
|
|
- ctx.restore();
|
|
|
+ ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
|
|
|
+ ctx.drawImage(this.image, 0, 0,this.canvasInfo.width,this.canvasInfo.height);
|
|
|
+
|
|
|
+ this.DrawDataInfo();//加载边框数据
|
|
|
+
|
|
|
},
|
|
|
|
|
|
// 更新缩放率
|
|
|
@@ -1174,7 +1411,6 @@ export default {
|
|
|
position: absolute;
|
|
|
cursor: pointer;
|
|
|
z-index: 9;
|
|
|
- // border:1px solid red;
|
|
|
img
|
|
|
{
|
|
|
width: 100%;
|