| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132 |
- <template>
- <div class="paper_container" ref="paperContainer" @mousedown="onMouseDown" @mousemove="onMouseMove" @mouseup="onMouseUp" @wheel="onWheel">
- <canvas id="paperCanvas" ref="paperCanvas" class="paper_canvas" @mouseleave="onCanvasLeave" :style="{transform: `rotate(${rotateDeg}deg)`}"></canvas>
- <div ref="imgContainer" :id="`imgContainer${imageIndex}`" class="img_container" :style="{transform: `rotate(${rotateDeg}deg)`}">
- <img v-if="paperImgUrl" :src="paperImgUrl" >
- </div>
- <div class="no_paper_url" v-if="paperImgUrl==''">
- <div>暂无答题卡</div>
- <!-- 暂无答题卡 -->
- <!-- 请先制作模版 -->
- </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('fitScreen')">适合屏幕</div>
- <div class="menu_item" @click="handleMenuAction('zoomIn')">放大(向上滚轮)</div>
- <div class="menu_item" @click="handleMenuAction('zoomOut')">缩小(向下滚轮)</div>
- </div>
- </div>
- </template>
- <script>
- import { throttle } from 'lodash';
- import { mmToPx } from '@/utils/common.js'
- export default {
- components: {
- },
- props:{
- drawData:{
- type:Array,
- default:()=>[]
- },//画的边框的数据
- paperInfo:{
- type:Object,
- default:()=>null
- },//纸张大小
- paperImgUrl:{
- type:String,
- default:''
- },//试卷地址相关信息
- currentId:{
- type:String,
- default:''
- },//当前选中的id
- isDrag:{
- type:Boolean,
- default:true
- },//是否可以拖动 默认可以拖动
- isWheel:{
- type:Boolean,
- default:true
- },//是否可以滚动放大、缩小 默认可以滚动
- isShowContextMenu:{
- type:Boolean,
- default:true
- },//是否显示右键菜单
- rotateDeg:{
- type:String,
- default:'0'
- },//答题卡方向
- isAbnormal:{
- type:Boolean,
- default:false
- },//是否异常处使用 区别 异常处理使用的地方 正常答案显示蓝色
- usedCardType:{
- type:Number,
- default:2
- },//默认三方卡 1 系统卡 2 三方卡
- currentPage:{
- type:Number,
- default:1
- },//当前页码 默认第一页
- downLoadName:{
- type:String,
- default:''
- },//下载图片的名称
- imageIndex:{//图片索引
- type:[String,Number],
- default:''
- },
- scoreFontSize:{
- type:Number,
- default:50
- },
- rtOrWrSize:{
- type:Number,
- default:2
- }
- },
- computed:{
- },
- data() {
- return {
- position: {
- x: 0,
- y: 0
- },//初始canvas图片位置
- startX: 0,//鼠标按下时的初始位置x坐标
- startY: 0,//鼠标按下时的初始位置y坐标
-
- scale: 1,//画布缩放倍数
- isDragging:false,//是否拖动画布
- isDrawing:false,//是否正在画线
-
- drawType:0,//1画线 0 拖拽模式
- image: null,
-
- paperImgInfo:{
- width:0,
- height:0
- },
- canvasInfo:{
- width:0,
- height:0
- },//画布的大小
- imageInfo:{
- width:0,
- height:0
- },//原始图片的大小
- canvas:null,//画板canvas
- ctx:null,//画板上下文
- zoomRate:0,//图片的缩放比例
- dpr:window.devicePixelRatio || 1,
- minScale:0.7,//最小缩放值
- maxScale:4,//最大缩放值
- rectPoint:{
- startX:0,
- startY:0,
- endX:0,
- endY:0
- },//矩形起始坐标点
- // 客观题区域
- showObjectArea:false,//是否显示对象区域
- addObjectAreaOption:{
- derection:1,//排列方向 1 横线 2竖向
- questionType:1,//题类型 1单选 2多选 3 判断
- startNumber:16,//起始题号
- endNumber:20,//结束题号
- interval:1,//题号间隔 默认1
- answerNumber:4,//选项个数 答案个数
- answerWidth:0,//选项宽度
- answerHeight:0,//选项高度
- },//添加选择题设置信息
- currenPoint:{
- x:0,
- y:0,
- w:0,
- h:0,
- },
- // isSelectBox:false,//是否选择框选答案区域框
- containerWidth:0,//容器宽度
- containerHeight:0,//容器高度
- isInit:true, //是否是初始加载
- showContextMenu: false,//是否显示右键菜单
- contextMenuX: 0, // 右键菜单X坐标
- contextMenuY: 0, // 右键菜单Y坐标
- CacheAllWrong:new Image(),//缓存的全错图片
- CacheAllRight:new Image(),//缓存的全对图片
- CacheHalfRight:new Image(),//缓存的半对图片
- CacheTypicalError:new Image(),//缓存的典型错误图片
- CacheExcellentAnswer:new Image(),//缓存的优秀答案图片
- jHeight:0,//跨页的标注 需要减去的高度
- blockList:[],//块列表
-
- }
- },
- watch:{
- paperImgUrl:
- {
- handler(newVal, oldVal)
- {
- console.log("地址变化了",this.paperImgUrl);
- if(this.paperImgUrl)
- {
- this.InitData();//初始化数据
- }
-
- },
- deep: true ,// 如果需要深度监听数组内部对象的变化
- listener: true//立即执行一次
- // console.log("地址变化了",this.paperImgUrl);
- // this.initData();//初始化数据
- },
- drawData:{
- handler(newVal, oldVal) {
-
- this.drawImage();//更新边框数据并重新绘制
- },
- deep: true // 如果需要深度监听数组内部对象的变化
- },//边框数据
- // currentId()
- // {
- // // console.log("当前选中项的id变化了",this.currentId);
- // this.drawImage();//更新边框数据并重新绘制
- // },
- },
- created(){
- this.CacheAllWrong.src=require('../assets/icon/icon_all_wrong.svg');
- this.CacheAllRight.src=require('../assets/icon/icon_all_right.svg');
- this.CacheHalfRight.src=require('../assets/icon/icon_half_right.svg');
- this.CacheTypicalError.src=require('../assets/tool/model_2.png');
- this.CacheExcellentAnswer.src=require('../assets/tool/model_1.png');
- this.CacheAllWrong.onload=()=>{
- };
- this.CacheAllRight.onload=()=>{
- };
- this.CacheHalfRight.onload=()=>{
- };
- this.CacheTypicalError.onload=()=>{
- };
- this.CacheExcellentAnswer.onload=()=>{
- };
- window.addEventListener('resize', this.handleResize);
- // 添加全局鼠标释放事件监听器,处理异常情况
- window.addEventListener('mouseup', this.onGlobalMouseUp);
- // 添加全局点击事件监听器,用于隐藏右键菜单
- document.addEventListener('click', this.handleGlobalEvent);
- // 添加全局右键点击事件监听器,用于隐藏右键菜单
- document.addEventListener('contextmenu', this.handleGlobalEvent);
- },
- beforeDestroy() {
-
- // 移除监听 防止内存泄漏
- window.removeEventListener('resize', this.handleResize);
- window.removeEventListener('mouseup', this.onGlobalMouseUp);
- document.removeEventListener('click', this.handleGlobalEvent);
- // 移除全局右键点击事件监听器
- document.removeEventListener('contextmenu', this.handleGlobalEvent);
- // 移除 paper_container 上的事件监听器
- if (this.$refs.paperContainer)
- {
- this.$refs.paperContainer.removeEventListener('contextmenu', this.handleRightClick);
- // this.$refs.paperContainer.removeEventListener('click', this.hideContextMenu);
- }
- },
- mounted() {
- this.InitData();//初始数据处理加载 如定位 居中 等 第一次居中
- // 确保 DOM 已经渲染后再添加事件监听器
- this.$nextTick(() => {
- if (this.$refs.paperContainer) {
- this.$refs.paperContainer.addEventListener('contextmenu', this.handleRightClick);
- // this.$refs.paperContainer.addEventListener('click', this.hideContextMenu);
- } else {
- console.error('paperContainer 未找到');
- }
- });
- },
- methods: {
- // 处理右键点击事件
- handleRightClick(event)
- {
- if(!this.isShowContextMenu) return false
- event.preventDefault();
- event.stopPropagation(); // 阻止事件继续向上冒泡
- // 设置菜单位置(相对于 paper_container 的位置)
- const containerRect = this.$refs.paperContainer.getBoundingClientRect();
- this.contextMenuX = event.clientX - containerRect.left;
- this.contextMenuY = event.clientY - containerRect.top;
- // 显示自定义菜单
- this.showContextMenu = true;
- },
- // 处理全局事件(包括左键点击和右键点击),用于隐藏菜单
- handleGlobalEvent(event) {
- // 检查点击的元素是否在菜单内部
- const menuElement = document.querySelector('.custom_context_menu');
-
- // 如果菜单是显示的,并且点击的元素不在菜单内部,则隐藏菜单
- if (this.showContextMenu && menuElement && !menuElement.contains(event.target)) {
- this.hideContextMenu();
- }
- },
-
- // 隐藏右键菜单
- hideContextMenu()
- {
- this.showContextMenu = false;
- },
- // 处理菜单项点击
- handleMenuAction(action)
- {
- console.log('执行操作:', action);
-
-
-
- switch(action) {
- case 'zoomIn':
- // 放大
- this.scale = Math.min(this.maxScale, this.scale + 0.1);
- this.ImageInfoChange();
- this.updateCanvasSize();
- this.drawImage();
- break;
- case 'zoomOut':
- // 缩小
- // 缩小
- this.scale = Math.max(this.minScale, this.scale - 0.1);
- this.ImageInfoChange();
- this.updateCanvasSize();
- this.drawImage();
- break;
- case 'fitScreen':
- //适合屏幕
- this.fitScreen()
- break;
- case 'download':
- // 下载图片
- this.downloadImage();
- break;
- }
- // 隐藏菜单
- this.hideContextMenu();
- },
- //下载图片功能
- downloadImage()
- {
-
- // this.DownloadDrawImage();
- // //将canvas 转换为data Url
- // const imgUrl =this.canvas.toDataURL('image/png');
- // //创建一个隐藏的a标签
- // let link = document.createElement('a');
- // link.href = imgUrl;
- // link.download = this.downLoadName+'.png';
- // // link.setAttribute('id', 'downloadImg');
- // // link.setAttribute('_blank', 'target');
- // //触发点击事件
- // document.body.appendChild(link);
- // link.click()
- // document.body.removeChild(link);
- // 创建一个新的canvas用于导出
- const exportCanvas = document.createElement('canvas');
- const exportCtx = exportCanvas.getContext('2d');
-
- // 设置导出canvas的尺寸与当前canvas相同
- exportCanvas.width = this.paperImgInfo.width;
- exportCanvas.height = this.paperImgInfo.height;
- console.log("画布宽高",this.canvasInfo.width,this.canvasInfo.height);
- console.log("图片宽高",this.paperImgInfo.width,this.paperImgInfo.height)
-
- // 在canvas上按当前显示尺寸绘制所有试卷图片
- exportCtx.drawImage(this.image, 0, 0, this.paperImgInfo.width, this.paperImgInfo.height);
- // 重新绘制标注信息到导出canvas上(按原始图片尺寸)
- this.DrawDataInfoCommon(exportCtx,1,1);//导出按原试卷尺寸
-
- // // 将当前canvas内容绘制到导出canvas上(这包括所有标记和注释)
- // exportCtx.drawImage(this.$refs.paperCanvas, 0, 0);
-
- // 将合并后的内容转换为data URL
- const imgUrl = exportCanvas.toDataURL('image/png');
-
- // 创建一个隐藏的a标签
- let link = document.createElement('a');
- link.href = imgUrl;
- link.download = this.downLoadName + '.png';
-
- // 触发点击事件
- document.body.appendChild(link);
- link.click();
- document.body.removeChild(link);
-
- },
- //导出绘制批注信息 公共方法 抽离成一个
- DrawDataInfoCommon(ctx,zoomRate,scale)
- {
-
- for(var i=0;i<this.drawData.length;i++)
- {
- let item=this.drawData[i];
- 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*zoomRate*scale,
- y:point.y*zoomRate*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//减去上下的边距
- };//模板去掉边框的尺寸
- }
- let imagePoint={};
- //客观题 需要减去 30 和25 因为客观题的坐标是相当于试卷原点 其他的主观题坐标是相当于批阅块的
- if(item.titleType==1)
- {
- imagePoint={
- x:((point.x-30)/templateInfo.width)*this.paperImgInfo.width,
- y:((point.y-15)/templateInfo.height)*this.paperImgInfo.height,
- };//相对于原图试卷的坐标 这里减去30是 黑块相对于左边的边距30px 上边的边距25px 减去15 是因为选择题的采分点 使用的是第一个答案的初始坐标点 需要减去答案的高度使其上下居中
- }
- else
- {
- imagePoint={
- x:(point.x/templateInfo.width)*this.paperImgInfo.width ,
- y:(point.y/templateInfo.height)*this.paperImgInfo.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("打印当前题目",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
- 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)
- // {
- // pageItem=item;
- // }
- // });
- //需要同时根据索引和页面查找
- // const pageItem = item.pagePaintingVOS.find(item => item.page == point.page && item.index == point.index);
- 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(pointPage != this.pointPage)
- {
- //如果不是同一页
- console.log("打印不同页的坐标 打印第一页的切块坐标",newBlockPoint);
- jHeight=newBlockPoint.h;
- }
- if (blockPoint) {
- obj.x =this.GetInteger(newBlockPoint.x* zoomRate * scale+ obj.x);
- obj.y =this.GetInteger(newBlockPoint.y* zoomRate * 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';
- if(item.questionName=='总分')
- {
- const fontSize = Math.max(12, this.scoreFontSize * scale); // 最小字体12px,基础字体50px
- ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
-
- ctx.textAlign = 'left';
- // 添加下划线
- let text = '',textWidth = 0;
- if(item.displayType === 0 || item.displayType === 2){
- text = item.displayName.toString();
- textWidth = ctx.measureText(text).width;
- }else{
- textWidth = 2 * fontSize*zoomRate*scale;
- }
- const underlineY = obj.y + 50*zoomRate * scale ; // 可根据需要调整下划线位置
- const startX = obj.x +35*zoomRate*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*zoomRate*scale);
- ctx.strokeStyle = ctx.fillStyle; // 使用与文字相同的颜色
- ctx.lineWidth = 4;
- ctx.stroke();
- if(item.displayType === 0 || item.displayType === 2){//0-分数 1-对错 2-等级
- ctx.fillText(item.displayName,obj.x+35*zoomRate*scale,obj.y);
- }else{
- //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
- const iconX=obj.x +35*zoomRate*scale;
- const iconY=obj.y-this.rtOrWrSize*fontSize*zoomRate*scale;
- const iconWidth = this.rtOrWrSize * fontSize*zoomRate*scale;
- const iconHeight = this.rtOrWrSize * fontSize*zoomRate*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{
- //半对
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
- }
- }
- }
- else
- {
- const fontSize = Math.max(12, 18 * scale); // 最小字体12px,基础字体18px
- // ctx.font = '30px Arial';
- ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
- ctx.textAlign = 'left';
- //判断是什么类型 scoreType 分数类型1:全对 2:半对 3: 全错
- const iconX=obj.x-20*zoomRate*scale;
- const iconY=obj.y-20*zoomRate*scale;
- const iconWidth = 40*zoomRate*scale;
- const iconHeight = 40*zoomRate*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*zoomRate*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 if(item.correctType==1){
- //半对
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
- }else{
- const displayName = isNaN(item.displayName)?0:Number(item.displayName);
- if(displayName==0){
- //0 分全错
- ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
- }else if(displayName==item.fullScore){
- //满分全对
- ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
- }else{
- //半对
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
- }
- }
- if(item.displayType === 0){//0-分数 显示分数和对错
- ctx.fillText(item.displayName,obj.x+35*zoomRate*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);
- if(blockList.length>0)
- {
- //跨页的
- let jh=0;//打印需要减去的高度 跨页的
- blockList.forEach((blockItem,index) => {
- console.log("打印blockItem",blockItem);
- if(blockItem.page==this.currentPage)
- {
- drawLineData.forEach((drawlineItem,drawIndex) => {
- let findIndex=this.FindBlockIndex(drawlineItem,blockList);
- console.log("打印drawIndex",drawIndex);
- console.log("打印findIndex",findIndex);
-
- let drawItem=drawlineItem;
- if(findIndex==index)
- {
- // drawItem=this.FindTargetObj(drawlineItem,blockList);
- blockPoint=blockList[findIndex];
-
-
- console.log("打印blockPoint",blockPoint);
- console.log("打印drawItem",drawItem);
- // 计算通用的缩放因子,避免重复计算
- const zoomScale = zoomRate * 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 - jh * zoomScale),
- endX: this.GetInteger(drawItem.endX * zoomScale + offsetX),
- endY: this.GetInteger(drawItem.endY * zoomScale + offsetY - jh * zoomScale)
- };
- this.DrawHorizontalLine(coords.x, coords.y, coords.endX, coords.endY,ctx);
- break;
- }
-
- case 3: {
- // 绘制波浪线
- const coords = {
- startX: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- startY: parseFloat(((drawItem.y-jh) * zoomScale + offsetY).toFixed(2)),
- endX: parseFloat((drawItem.endX * zoomScale + offsetX).toFixed(2)),
- endY: parseFloat(((drawItem.endY-jh) * zoomScale + offsetY).toFixed(2))
- };
- this.DrawWaveLine(coords.startX, coords.startY, coords.endX, coords.endY,ctx);
- break;
- }
-
- case 4:
- // 绘制画笔数据
- this.DrawPenLine(drawItem,blockPoint,zoomRate,scale,ctx);
- 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,ctx);
- break;
- }
- case 6:
- {
- // 绘制对号
- const coords = {
- x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
- };
- this.DrawText(coords.x, coords.y, '✔',ctx);
- break;
- }
- case 7: {
- // 绘制对号
- const coords = {
- x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
- };
- this.DrawText(coords.x, coords.y, '✘',ctx);
- break;
- }
- default:
- console.warn('未知的绘图类型:', drawItem.drawType);
- }
- }
-
- })
- }
- jh=jh+blockItem.h;
- });
- }
- else
- {
- //非跨页的数据
- for(const [index, drawItem] of drawLineData.entries()) {
- console.log("打印drawItem",drawItem);
- // 计算通用的缩放因子,避免重复计算
- const zoomScale = zoomRate * 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,ctx);
- 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,ctx);
- break;
- }
-
- case 4:
- // 绘制画笔数据
- this.DrawPenLine(drawItem,blockPoint,zoomRate,scale,ctx);
- 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,ctx);
- break;
- }
- case 6:
- {
- // 绘制对号
- const coords = {
- x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
- };
- this.DrawText(coords.x, coords.y, '✔',ctx);
- break;
- }
- case 7: {
- // 绘制对号
- const coords = {
- x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
- };
- this.DrawText(coords.x, coords.y, '✘',ctx);
- break;
- }
-
- default:
- console.warn('未知的绘图类型:', drawItem.drawType);
- }
- }
- }
-
-
- }
-
-
-
-
- }
- },
- //寻找对象在数组中的索引
- FindBlockIndex(targetObj,arr)
- {
- // 累计高度,用来确定对象位于哪个区间
- let cumulativeHeight = 0;
-
- for (let i = 0; i < arr.length; i++) {
- const item = arr[i];
- if(targetObj.drawType==4)
- {
- //画笔判断
- if (targetObj.drawlineData[0].y >= cumulativeHeight && targetObj.drawlineData[0].y < cumulativeHeight + item.h) {
-
- return i; // 返回匹配的索引
- }
- }
- else
- {
- // 检查目标对象的y值是否在当前区间的范围内
- if (targetObj.y >= cumulativeHeight && targetObj.y < cumulativeHeight + item.h) {
- return i; // 返回匹配的索引
- }
- }
-
-
- // 累计高度,为下一个区间的起始位置
- cumulativeHeight += item.h;
- }
-
- return -1; // 如果没有找到匹配的区间,返回-1
- },
- //寻找对象在数组中的对象
- FindTargetObj(targetObj,arr)
- {
- // 累计高度,用来确定对象位于哪个区间
- let cumulativeHeight = 0;
-
- for (let i = 0; i < arr.length; i++) {
- const item = arr[i];
-
-
- // 判断画笔
- if(targetObj.drawType==4)
- {
-
- if (targetObj.drawlineData[0].y >= cumulativeHeight && targetObj.drawlineData[0].y < cumulativeHeight + item.h) {
-
- targetObj.drawlineData.forEach((item,index) => {
- item.y=item.y-cumulativeHeight;
- });
- }
- }
- else
- {
- // 检查目标对象的y值是否在当前区间的范围内
- if (targetObj.y >= cumulativeHeight && targetObj.y < cumulativeHeight + item.h) {
- targetObj.y=targetObj.y-cumulativeHeight;
-
- }
- }
-
- // 累计高度,为下一个区间的起始位置
- cumulativeHeight += item.h;
- }
-
- return targetObj;
- },
- //初始数据加载
- InitData()
- {
- //获取容器的宽高
- const { width, height } = this.$refs.paperContainer.getBoundingClientRect();
-
- this.containerHeight = Number(height);
- this.containerWidth =Number(width);
- console.log("容器宽高",this.containerWidth,this.containerHeight);
- //初始化获取试卷数据
- console.log("打印paperInfo",this.paperInfo);
- if(this.paperInfo?.width && this.paperInfo?.height)
- {
- //设置初始数据
- this.paperImgInfo.width=this.paperInfo.width;//获取宽
- this.paperImgInfo.height=this.paperInfo.height;//获取高
- // 更新缩放率
- this.updateZoomAndPaperInfo();
- // 更新画布尺寸
- this.updateCanvasSize();
- console.log("是否初始",this.isInit);
- //计算中心位置使图片居中 初始加载图片是居中
- if(this.isInit)
- {
- this.centerCanvas();
- }
-
-
-
- //加载图片
- this.loadImage();
- }
- else
- {
- //没有值 默认图片的宽高
- console.log("没有纸张试卷的宽高信息");
- this.image = new Image();
- this.image.crossOrigin = 'anonymous'; // 处理跨域问题
- this.image.src = this.paperImgUrl;
- this.image.onload = () => {
- console.log("图片加载完成",this.image);
- this.paperImgInfo.width=this.image.width;//获取宽
- this.paperImgInfo.height=this.image.height;//获取高
-
- // 更新缩放率
- this.updateZoomAndPaperInfo();
- // 更新画布尺寸
- this.updateCanvasSize();
- //计算中心位置使图片居中
- console.log("是否初始",this.isInit);
- //计算中心位置使图片居中 初始加载图片是居中
- // if(this.isInit)
- // {
- this.centerCanvas();
- // }
- //加载图片
- this.loadImage();
- // this.drawQuestionPosition();
- };
- }
-
-
- },
- //切换试卷图片
- chanagePaperImage()
- {
- // 更新缩放率
- this.updateZoomAndPaperInfo();
- // 更新画布尺寸
- this.updateCanvasSize();
- // //计算中心位置使图片居中
- // this.centerCanvas();
- //加载图片
- this.loadImage();
- },
- //适合屏幕
- fitScreen()
- {
- this.scale=1;
- this.isInit=true;
- this.InitData();//初始化屏幕加载
- },
-
- // 加载图片
- loadImage() {
- // this.image = new Image();
- // this.image.src = this.paperImgUrl;
- // this.image.onload = () => {
- // console.log("图片加载完成",this.image);
- this.drawImage();//绘制边框数据
-
- // this.drawQuestionPosition();
- // };
- },
-
- // 图片宽高坐标变化
- ImageInfoChange(){
- let {width,height} = this.paperImgInfo;
- // console.log("打印纸张试卷的图片宽高",this.paperImgInfo);
- // let imgDom = document.getElementById(`imgContainer${this.imageIndex}`);
- // imgDom.style.width = width * this.zoomRate*this.scale + 'px';
- // imgDom.style.height = height * this.zoomRate*this.scale + 'px';
- // imgDom.style.left = this.position.x + 'px';
- // imgDom.style.top = this.position.y + 'px';
- let imgDom = this.$refs.imgContainer;
- imgDom.style.width = width * this.zoomRate*this.scale + 'px';
- imgDom.style.height = height * this.zoomRate*this.scale + 'px';
- imgDom.style.left = this.position.x + 'px';
- imgDom.style.top = this.position.y + 'px';
- },
- //图片加载完成后绘制图片
- drawImage()
- {
- // if (this.image) {
- this.canvas=this.$refs.paperCanvas;
- let ctx = this.canvas.getContext('2d');
- ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);//清除边框数据
-
- this.ImageInfoChange();//用image图片替代背景 是为了高清显示
-
- console.log("加载边框数据",this.drawData);
- // this.DrawDataInfo();//加载边框数据
- this.DrawDataInfoCommon(ctx,this.zoomRate,this.scale);
- },
- //绘制批注信息 此方法已弃用 改用DrawDataInfoCommon 公共
- 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);//原始采分点的坐标
-
- 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(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//减去上下的边距
- };//模板去掉边框的尺寸
- }
- let imagePoint={};
- //客观题 需要减去 30 和25 因为客观题的坐标是相当于试卷原点 其他的主观题坐标是相当于批阅块的
- if(item.titleType==1)
- {
- imagePoint={
- x:((point.x-30)/templateInfo.width)*this.paperImgInfo.width,
- y:((point.y-15)/templateInfo.height)*this.paperImgInfo.height,
- };//相对于原图试卷的坐标 这里减去30是 黑块相对于左边的边距30px 上边的边距25px 减去15 是因为选择题的采分点 使用的是第一个答案的初始坐标点 需要减去答案的高度使其上下居中
- }
- else
- {
- imagePoint={
- x:(point.x/templateInfo.width)*this.paperImgInfo.width ,
- y:(point.y/templateInfo.height)*this.paperImgInfo.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("打印当前题目",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
- 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)
- // {
- // pageItem=item;
- // }
- // });
- //需要同时根据索引和页面查找
- // const pageItem = item.pagePaintingVOS.find(item => item.page == point.page && item.index == point.index);
- 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(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';
- if(item.questionName=='总分')
- {
- const fontSize = Math.max(12, this.scoreFontSize * this.scale); // 最小字体12px,基础字体50px
- ctx.font = `${fontSize}px Arial`; // 让文字大小跟随缩放
-
- ctx.textAlign = 'left';
- // 添加下划线
- 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){//0-分数 1-对错 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-this.rtOrWrSize*fontSize*this.zoomRate*this.scale;
- const iconWidth = this.rtOrWrSize * fontSize*this.zoomRate*this.scale;
- const iconHeight = this.rtOrWrSize * 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{
- //半对
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
- }
- }
- }
- else
- {
- 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 = 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 分全错
- ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
- }else if(item.correctType==2){
- //满分 全对
- ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
- }else if(item.correctType==1){
- //半对
- ctx.drawImage(this.CacheHalfRight, iconX, iconY, iconWidth, iconHeight);
- }else{
- const displayName = isNaN(item.displayName)?0:Number(item.displayName);
- if(displayName==0){
- //0 分全错
- ctx.drawImage(this.CacheAllWrong, iconX, iconY, iconWidth, iconHeight);
- }else if(displayName==item.fullScore){
- //满分全对
- ctx.drawImage(this.CacheAllRight, iconX, iconY, iconWidth, iconHeight);
- }else{
- //半对
- 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);
- }
- }
- }
- // 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;
- }
- case 6: {
- // 绘制对号
- const coords = {
- x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
- };
- this.DrawText(coords.x, coords.y, '✔');
- break;
- }
- case 7: {
- // 绘制错号
- const coords = {
- x: parseFloat((drawItem.x * zoomScale + offsetX).toFixed(2)),
- y: parseFloat((drawItem.y * zoomScale + offsetY).toFixed(2))
- };
- this.DrawText(coords.x, coords.y, '✘');
- break;
- }
-
- default:
- console.warn('未知的绘图类型:', drawItem.drawType);
- }
- }
-
- }
-
-
-
-
- }
- },
- //转成整数
- 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);
- },
- //画横线
- DrawHorizontalLine(x1,y1,x2,y2,ctx = null)
- {
- console.log("画横线起始坐标点",x1, y1, x2, y2);
- // 如果没有传入上下文,则使用当前canvas的上下文
- const canvasContext = ctx || this.$refs.paperCanvas.getContext('2d');
- canvasContext.strokeStyle = 'red';//设置红色
- canvasContext.lineWidth = 2;//线条宽度
- canvasContext.beginPath();
- canvasContext.moveTo(x1, y1);
- canvasContext.lineTo(x2, y2);
- canvasContext.stroke();
- },
- //画波浪线
- DrawWaveLine(startX, startY, endX, endY,ctx = null)
- {
- // console.log("画波浪线起始坐标点",startX, startY, endX, endY);
- const amplitude = 2; // 波浪的宽度
- const frequency = 0.8; //振幅 越大越密集
- //计算中间点
- const dx=endX-startX;
- const dy=endY-startY;
- // 如果没有传入上下文,则使用当前canvas的上下文
- const canvasContext = ctx || this.$refs.paperCanvas.getContext('2d');
- canvasContext.strokeStyle = 'red';//设置红色
- canvasContext.lineWidth = 2;//线条宽度
- // 清除之前的线条
- // ctx.clearRect(0, 0, this.canvasInfo.width, this.canvasInfo.height);
- canvasContext.beginPath();
- canvasContext.moveTo(startX, startY);//绘制第一个点
- //绘制波浪
- // 绘制波浪线
- for (let x = startX; x <= endX; x += 1) {
- const y = startY + dy * (x - startX) / dx + amplitude * Math.sin(frequency * (x - startX));
- canvasContext.lineTo(x, y);
- }
- // ctx.lineTo(endX, endY);//绘制最后一个点
- // ctx.lineWidth = 2; // 设置线条宽度
- canvasContext.stroke();
- },
- //绘制画笔数据
- DrawPenLine(data,blockPoint,zoomRate,scale, ctx = null)
- {
-
- console.log("打印绘制画笔数据",data);
- let linelist=data.drawlineData;
- if(linelist.length>0)
- {
- // 如果没有传入上下文,则使用当前canvas的上下文
- const canvasContext = ctx || this.$refs.paperCanvas.getContext('2d');
- canvasContext.strokeStyle = 'red';//设置红色
- canvasContext.lineWidth = 2;//线条宽度
- // 开始绘制
- canvasContext.beginPath();
-
- // 绘制路径
- for (let i = 0; i < linelist.length; i++) {
- if(blockPoint)
- {
- let x=parseFloat(((linelist[i].x + blockPoint.x)* zoomRate * scale).toFixed(2));
- let y=parseFloat(((linelist[i].y + blockPoint.y)* zoomRate * scale).toFixed(2));
- canvasContext.lineTo(x, y);
- }
-
- }
- canvasContext.stroke();
- canvasContext.closePath();
- }
- },
- //绘制文字
- DrawText(startX, startY, text , ctx = null)
- {
- // 如果没有传入上下文,则使用当前canvas的上下文
- const canvasContext = ctx || this.$refs.paperCanvas.getContext('2d');
- // 设置字体样式
- canvasContext.font = '15px Arial';
- canvasContext.fillStyle = 'red';
- canvasContext.textAlign = 'left';
- // ctx.textBaseline = 'middle';
- // 绘制文字
- canvasContext.fillText(text,startX, startY);
- },
- //下载图片绘制
- 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);
- this.DrawDataInfo();//加载边框数据
- },
- // 更新缩放率
- updateZoomAndPaperInfo() {
- // this.zoomRate = this.containerHeight / this.paperImgInfo.height;//
- // 计算基于宽度和高度的缩放率
- let widthZoomRate = 1;
- let heightZoomRate = 1;
- if(this.rotateDeg=='-90'){//旋转90度 学生报告册使用
- widthZoomRate = this.containerWidth / this.paperImgInfo.height;
- heightZoomRate = (this.containerHeight - 40) / this.paperImgInfo.width;//减掉报告册底边距40px
- }else{
- widthZoomRate = this.containerWidth / this.paperImgInfo.width;
- heightZoomRate = this.containerHeight / this.paperImgInfo.height;
- }
-
- // 选择较小的缩放率作为基准,确保图像完整显示在容器内
- this.zoomRate = Math.min(widthZoomRate, heightZoomRate);
-
- // this.paperImgInfo = this.cardType ==1 ? { width: 1240, height: 1754 } : { width: 2480, height: 1754 };
- // console.log("打印this.paperImgInfo",this.paperImgInfo);
- },
- // 更新画布尺寸
- updateCanvasSize()
- {
- this.canvasInfo.width = Math.round(this.paperImgInfo.width * this.zoomRate * this.scale);
- this.canvasInfo.height = Math.round(this.paperImgInfo.height * this.zoomRate * this.scale);
- this.$refs.paperCanvas.width = this.canvasInfo.width;
- this.$refs.paperCanvas.height = this.canvasInfo.height;
- },
- // 中心化画布
- centerCanvas()
- {
- console.log("开始居中画布",this.containerWidth,this.containerHeight);
- console.log("画布尺寸",this.canvasInfo.width,this.canvasInfo.height);
- this.position.x = (this.containerWidth - this.canvasInfo.width) / 2;
- if(this.rotateDeg=='-90'){//学生报告册使用
- this.position.y = (this.containerHeight - this.canvasInfo.height) / 2 - 40;
- }else{
- this.position.y = (this.containerHeight - this.canvasInfo.height) / 2;
- }
- this.$refs.paperCanvas.style.left = `${this.position.x}px`;
- this.$refs.paperCanvas.style.top = `${this.position.y}px`;
- console.log("中心化画布打印画布位置",this.position.x,this.position.y);
- this.isInit=false;//后面不在执行居中操作
- },
- // 全局鼠标释放事件处理
- onGlobalMouseUp() {
- this.isDragging = false;
- },
- // 鼠标按下事件
- onMouseDown(event) {
- // 只响应左键点击(button值为0表示左键)
- if (event.button !== 0) {
- // 如果是右键,确保释放拖拽状态
-
- this.isDragging = false;
- return;
- }
- console.log("鼠标按下事件",event);
- // 确保在开始新的拖拽前,先重置拖拽状态
- this.isDragging = false;
- console.log("鼠标按下事件drawType",this.drawType);
- if(this.drawType==0)
- {
- // 如果drawType==0,则切换到拖拽模式
- console.log("打印是否可拖拽",this.isDrag);
- if(this.isDrag)
- {
- console.log("开始拖拽");
- console.log("打印开始拖拽的坐标",this.startX,this.startY);
- console.log("打印鼠标位置",event.clientX,event.clientY);
- console.log("打印画布位置",this.position.x,this.position.y);
- //可拖动的时候才能拖动
- this.isDragging = true;
- this.startX = event.clientX - this.position.x;
- this.startY = event.clientY - this.position.y;
- console.log("打印开始拖拽的坐标",this.startX,this.startY);
- }
-
-
- }
- if(this.drawType==1)
- {
- if(event.target.id!='paperCanvas')
- {
- this.isDragging = true;
- this.startX = event.clientX - this.position.x;
- this.startY = event.clientY - this.position.y;
- }
- }
- },
- // 鼠标移动事件
- onMouseMove(event)
- {
- if (this.isDragging)
- {
- // 在拖拽模式下,移动画布
- this.position.x = event.clientX - this.startX;
- this.position.y = event.clientY - this.startY;
- this.$refs.paperCanvas.style.left = `${this.position.x}px`;
- this.$refs.paperCanvas.style.top = `${this.position.y}px`;
- this.ImageInfoChange();
- }
- },
- // 鼠标抬起事件
- onMouseUp(event) {
- // 只响应左键释放
- if (event && event.button !== 0) {
- return;
- }
- this.isDragging = false; // 停止拖拽
-
- },
- // // 鼠标滚轮事件
- // onWheel(event) {
- // event.preventDefault();
- // const delta = event.deltaY < 0 ? 1 : -1;
- // const newScale = this.scale + delta * 0.1;
- // this.scale = Math.max(this.minScale, Math.min(this.maxScale, newScale));
-
- // this.ImageInfoChange();
- // this.updateCanvasSize();
- // this.drawImage();
- // },
- // 鼠标滚轮事件
- onWheel(event) {
- if(!this.isWheel) return false
- event.preventDefault();
- // 计算新的缩放比例
- const delta = event.deltaY < 0 ? 1 : -1;
- const newScale = this.scale + delta * 0.1;
- const clampedScale = Math.max(this.minScale, Math.min(this.maxScale, newScale));
-
- // 如果缩放值没有变化,则直接返回
- if (clampedScale === this.scale) return;
-
- // 获取鼠标在容器中的位置
- const containerRect = this.$refs.paperContainer.getBoundingClientRect();
- const mouseX = event.clientX - containerRect.left;
- const mouseY = event.clientY - containerRect.top;
-
- // 计算鼠标相对于当前画布的位置
- const mouseRelativeToCanvasX = (mouseX - this.position.x) / this.scale;
- const mouseRelativeToCanvasY = (mouseY - this.position.y) / this.scale;
-
- // 更新缩放比例
- this.scale = clampedScale;
-
- // 更新画布尺寸
- this.updateCanvasSize();
-
- // 重新计算画布位置,使缩放围绕鼠标点进行
- this.position.x = mouseX - mouseRelativeToCanvasX * this.scale;
- this.position.y = mouseY - mouseRelativeToCanvasY * this.scale;
-
- // 应用新的位置
- this.$refs.paperCanvas.style.left = `${this.position.x}px`;
- this.$refs.paperCanvas.style.top = `${this.position.y}px`;
-
- // 更新图片位置信息
- this.ImageInfoChange();
-
- // 重新绘制内容
- this.drawImage();
- },
- //鼠标复位
- MouseReset()
- {
- this.drawType=0;
- this.canvas=this.$refs.paperCanvas;
- this.canvas.style.cursor="pointer";
- this.canvas.onmousedown=null;
- this.canvas.onmousemove=null;
- this.canvas.onmouseup=null;
- },
- //框选答案区域
- SelectionBox()
- {
- console.log("开始框选答案区域");
- this.drawType=1;
- this.canvas=this.$refs.paperCanvas;
- this.canvas.style.cursor="crosshair";
- this.canvas.onmousedown=this.onCanvasDown;
- this.canvas.onmousemove=this.onCanvasMove;
- this.canvas.onmouseup=this.onCanvasUp;
- },
-
- //画圈模式
- PaintingCircle()
- {
- console.log("进入画圈模式");
- this.drawType=1;
- this.canvas=this.$refs.paperCanvas;
- this.canvas.style.cursor="crosshair";
- this.canvas.onmousedown=this.onCanvasDown;
- this.canvas.onmousemove=this.onCanvasMove;
- this.canvas.onmouseup=this.onCanvasUp;
- },
- //开始画答案区域圈
- StartPaintingCircle(obj)
- {
- this.addObjectAreaOption=obj;
- this.drawType=1;
- this.canvas=this.$refs.paperCanvas;
- this.canvas.style.cursor="crosshair";
- this.canvas.onmousedown=this.onCanvasDown;
- this.canvas.onmousemove=this.onCanvasMove;
- this.canvas.onmouseup=this.onCanvasUp;
- },
- //canvas上按下事件
- onCanvasDown(e)
- {
- this.canvas.style.cursor="crosshair";
- this.isDrawing=true;
- this.isDragging = false; // 禁止拖拽
- this.rectPoint={
- startX:e.offsetX,
- startY:e.offsetY,
- endX:e.offsetX,
- endY:e.offsetY
- };
- },
- //canvas上移动事件
- onCanvasMove(e)
- {
- // this.drawType=1;
- // this.isDragging=true;
- if(this.isDrawing)
- {
- // const canvas = this.$refs.paperCanvas;
- // const ctx = canvas.getContext('2d');
- // // 计算矩形的宽度和高度
- // const width = e.offsetX - this.rectPoint.startX;
- // const height = e.offsetY - this.rectPoint.startY;
- // this.rectPoint.endX=e.offsetX;
- // this.rectPoint.endY=e.offsetY;
- // // 清除之前的矩形
- // ctx.clearRect(0, 0, canvas.width, canvas.height);
- // // 重新绘制之前的边框数据
- // this.drawImage();
- // // 设置矩形样式
- // ctx.strokeStyle = 'blue';
- // ctx.lineWidth = 1;//画框的线的粗细
- // // 绘制矩形
- // ctx.strokeRect(this.rectPoint.startX, this.rectPoint.startY, width, height);
- const canvas = this.$refs.paperCanvas;
- const ctx = canvas.getContext('2d');
- // 更新当前鼠标位置
- this.rectPoint.endX = e.offsetX;
- this.rectPoint.endY = e.offsetY;
-
- // 清除之前的矩形
- ctx.clearRect(0, 0, canvas.width, canvas.height);
- // 重新绘制之前的边框数据
- this.drawImage();
- // 设置矩形样式
- ctx.strokeStyle = 'blue';
- ctx.lineWidth = 1;//画框的线的粗细
-
- // 计算矩形的起点和宽高,处理反向框选
- const startX = this.rectPoint.startX;
- const startY = this.rectPoint.startY;
- const width = e.offsetX - startX;
- const height = e.offsetY - startY;
-
- // 绘制矩形(可以处理负宽度和高度)
- ctx.strokeRect(startX, startY, width, height);
- }
- },
- //canvas抬起事件
- onCanvasUp()
- {
- this.isDrawing = false;
- // console.log("鼠标抬起事件,画圈完成,打印四角坐标",this.rectPoint);
-
- // let point={
- // x:this.$global.floatNum((this.rectPoint.startX)/this.zoomRate/this.scale),
- // y:this.$global.floatNum(this.rectPoint.startY/this.zoomRate/this.scale),
- // w:this.$global.floatNum((this.rectPoint.endX-this.rectPoint.startX)/this.zoomRate/this.scale),
- // h:this.$global.floatNum((this.rectPoint.endY-this.rectPoint.startY)/this.zoomRate/this.scale),
- // unit:'px',
- // };//坐标还原成px单位
- // this.currenPoint=point;
- // console.log("打印当前坐标",point);
- // if(point.w>0 && point.h>0)
- // {
- // console.log("打印当前坐标",point);
-
-
- // this.$emit("GetRectPoint",point);
-
-
- // }
- // 处理反向框选,确保宽度和高度为正数
- let startX = this.rectPoint.startX;
- let startY = this.rectPoint.startY;
- let endX = this.rectPoint.endX;
- let endY = this.rectPoint.endY;
-
- // 确保起点坐标是左上角,终点坐标是右下角
- let actualStartX = Math.min(startX, endX);
- let actualStartY = Math.min(startY, endY);
- let actualEndX = Math.max(startX, endX);
- let actualEndY = Math.max(startY, endY);
-
- // 计算实际的宽度和高度(确保为正数)
- let width = Math.abs(actualEndX - actualStartX);
- let height = Math.abs(actualEndY - actualStartY);
-
- let point = {
- x: this.$global.floatNum(actualStartX / this.zoomRate / this.scale),
- y: this.$global.floatNum(actualStartY / this.zoomRate / this.scale),
- w: this.$global.floatNum(width / this.zoomRate / this.scale),
- h: this.$global.floatNum(height / this.zoomRate / this.scale),
- unit: 'px',
- };//坐标还原成px单位
-
- this.currenPoint = point;
- console.log("打印当前坐标", point);
-
- // 只有当宽度和高度都大于0时才触发事件
- if (point.w > 0 && point.h > 0) {
- console.log("打印当前坐标", point);
- this.$emit("GetRectPoint", point);
- }
-
-
- },
- //鼠标离开画布事件
- onCanvasLeave()
- {
- console.log("鼠标离开画布事件");
- // 如果正在绘制,自动结束绘制
- if (this.isDrawing) {
- this.onCanvasUp();
- }
- },
- // 监听窗口大小变化,重新计算表格高度 使用节流防止频繁改变窗口大小导致计算量过大而页面卡顿
- handleResize: throttle(function() {
-
- // //窗口变化重新计算canvas的宽高
- // let {width,height} = this.$refs.paperContainer.getBoundingClientRect();
- // this.updateZoomAndPaperInfo(height);
- // this.updateCanvasSize(width, height);
- // this.centerCanvas();
- // this.loadImage();
- }, 500), // 节流 500 毫秒内最多执行一次
- }
- }
- </script>
- <style lang="scss" scoped>
- .paper_container
- {
- width: 100%;
- height: 100%;
- overflow: hidden;
- position: relative;
- .paper_canvas
- {
- position: absolute;
- cursor: pointer;
- background-color: transparent;
- z-index: 10;//使canvas在图片上方
- }
- .img_container
- {
- position: absolute;
- cursor: pointer;
- z-index: 9;
- display: flex;
- flex-direction: column;
- img
- {
- width: 100%;
- height: 100%;
- }
- }
- //自定义右键菜单层样式
- .custom_context_menu
- {
- position: absolute;
- background: white;
- border: 1px solid #ccc;
- border-radius: 4px;
- box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
- z-index: 9999;
- min-width: 120px;
- .menu_item
- {
- padding: 8px 16px;
- cursor: pointer;
- font-size: 14px;
-
- &:hover {
- background-color: #f5f5f5;
- }
-
- &:not(:last-child) {
- border-bottom: 1px solid #eee;
- }
- }
- }
- }
- .no_paper_url {
- background-image: url("../assets/bg/no_content_bg.png");
- background-repeat: no-repeat;
- background-size: 360px auto;
- background-position: 50% 30%;
- color: #666666;
- width: 100%;
- height: 100%;
- justify-content: center;
- display: flex;
- align-items: center;
- }
- </style>
|