vue2使用fabric实现简单画图demo,完成批阅功能

news/发布时间2024/9/20 8:11:14

这个功能主要实现批阅的,修改上传的图片,标记内容

看看效果图

主要是根据fabric这个库来进行完成的

下载包

npm i fabric

组件内注册使用

import { fabric } from 'fabric';

步骤

body中

  <divv-if="imgs.length"class="canvas-wraper"style="overflow-y: auto; position: relative"><div class="lefts1" @click="changeZuo(1)">{{ zuo }}</div>  // 左切换按钮<div style="overflow: auto"><canvas id="canvas" ref="canvas"> </canvas>  // 动态的渲染画布</div><div class="lefts" @click="changeZuo(2)"> {{ you }}</div>  // 右切换按钮</div><div v-else class="canvas-wraper">  // 如果没有图片显示空<a-empty /></div></div><div style="background: #fff; padding: 20px; flex: 1"><divstyle="background: #f2f4f8; height: 100%; width: 100%; padding: 10px"><div><color-picker @changeColor="changeColors" @changeCuxi="changeCuxi"   // 使用的颜色库/></div><a-dividerdashedstyle="border-color: rgb(204, 204, 204); margin-top: 10px"/><div style="margin: 10px 0"><div>预习报告</div><div><template v-for="(item, index) in yxReportFileUrl"><imgclass="reportImg":src="item.url"@click="changeImg(item.url, index)"/></template></div></div><a-dividerdashedstyle="border-color: rgb(204, 204, 204); margin-top: 10px"/><div style="margin: 10px 0"><div>实操作及课后报告</div><div><template v-for="(item, index) in reportFileUrl"><imgclass="reportImg":src="item.url"@click="changeImg(item.url, yxReportFileUrl.length - 1 + index)"/></template></div></div><a-dividerdashedstyle="border-color: rgb(204, 204, 204); margin-top: 10px"/><div style="margin: 10px 0"><div style="display: flex; align-items: center"><div style="margin-right: 10px">预习分数:</div><a-inputv-model:value="reportData.prepareScore"placeholder="请输入"style="width: 300px"/></div></div><a-dividerdashedstyle="border-color: rgb(204, 204, 204); margin-top: 10px"/><div style="margin: 10px 0"><div style="display: flex; align-items: center"><div style="margin-right: 10px">操作分数:</div><a-inputv-model:value="reportData.experimentScore"placeholder="请输入"style="width: 300px"/></div></div><a-dividerdashedstyle="border-color: rgb(204, 204, 204); margin-top: 10px"/><div style="margin: 10px 0"><div style="display: flex; align-items: center"><div style="margin-right: 10px">课后分数:</div><a-inputv-model:value="reportData.reportScore"placeholder="请输入"style="width: 300px"/></div></div><a-dividerdashedstyle="border-color: rgb(204, 204, 204); margin-top: 10px"/><!--        三个按钮,上一个,下一个,返回课程列表页--><div style="margin: 30px 0"><a-buttonstyle="background: #2d8cf0; color: #fff; border-radius: 6px"@click="changeUser(1)">上一个</a-button><a-buttonstyle="margin: 0 30px;background: #19be6b;color: #fff;border-radius: 6px;"@click="changeUser(2)">下一个</a-button><a-button@click="goBack"style="background: #2d8cf0; color: #fff; border-radius: 6px">返回课程列表页</a-button></div><!--        <div class="download">-->   //  可以进行查看当前批阅后的图片<!--          <button type="button" :disabled="done" @click="downLoadImage">--><!--            转换为base64并预览--><!--          </button>--><!--          <img :src="imageBase64" v-show="imageBase64 != ''" alt="" />--><!--        </div>--></div>

js部分,主要是把要批阅的图片设置为背景图片进行标记批阅

<script>import { fabric } from 'fabric';import ColorPicker from '@/views/marking-report/components/color-picker.vue';import { changeColor } from 'ele-admin-pro/es';import ScorePicker from '@/views/marking-report/components/score-picker.vue';import {getCourseScore,pyStudentScore,updateCourseScoreById} from '@/api/marking-report';import { message } from 'ant-design-vue/es';import { uploadBase64File } from '@/api/system/file';// import { formatDate } from '@vueuse/shared';export default {components: { ScorePicker, ColorPicker },// 获取propsprops: ['data', 'data1'],data() {return {userIndex: 0,student: [],imgBase64: undefined,currentTool: '',yxReportFileUrl: [],reportFileUrl: [],imgs: [],imgsIndex: 0,currentImg: new Image(),done: false,fabricObj: null,initIdx: 0,zuo: '<',you: '>',toolsArr: [{ name: 'pencil', icon: ' icon-pencil', keyBoard: 'A' },{ name: 'duigou1', icon: 'icon-duigou1', keyBoard: 'B' },{ name: 'cuowu', icon: 'icon-cuowu', keyBoard: 'C' },{ name: 'line', icon: ' icon-line', keyBoard: 'D' },{ name: 'arrow', icon: ' icon-arrow', keyBoard: 'E' },{ name: 'xuxian', icon: ' icon-xuxian', keyBoard: 'F' },{ name: 'text', icon: ' icon-ziti', keyBoard: 'G' },{ name: 'juxing', icon: ' icon-juxing', keyBoard: 'H' },{ name: 'cricle', icon: ' icon-yuanxing', keyBoard: 'I' },{ name: 'ellipse', icon: ' icon-tuoyuanxing', keyBoard: 'J' },{ name: 'equilateral', icon: ' icon-sanjiaoxing', keyBoard: 'K' },{ name: 'remove', icon: ' icon-remove' },{ name: 'reset', icon: ' icon-reset' }],mouseFrom: {},mouseTo: {},moveCount: 1,doDrawing: false,fabricHistoryJson: [],mods: 0,drawingObject: null, //绘制对象drawColor: '#E34F51',drawWidth: 2,imageBase64: '',zoom: window.zoom ? window.zoom : 1,reportData: {},scoreId: ''};},computed: {canvasWidth() {return window.innerWidth;}},created() {},mounted() {this.getStudentScore();},beforeDestroy() {document.removeEventListener('keydown', this.onKeyDown);},methods: {// 切换学生changeUser(type) {//   根据type来区分上一个下一个,userIndex来进行切换if (type == 1) {if (this.userIndex == 0) {message.error('已经是第一个了');return;}this.userIndex--;// 保存当前图片跟分数// 调用downLoadImage方法得到转换后的图片;this.downLoadImage();setTimeout(() => {// 设置一个变量跟改变了的图片进行拼接let aa = this.imgs;aa[this.imgsIndex].url = this.imgBase64;// 遍历图片的url进行拼接let imgRes = '';if (this.imgs[this.imgsIndex].type == 're') {aa.forEach((item, index) => {if (item.type == 're') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});} else {aa.forEach((item, index) => {if (item.type == 'yx') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});}console.log(this.userIndex, 'this.userIndex');if (this.imgs[this.imgsIndex].type == 're') {updateCourseScoreById({scoreId: this.student[this.userIndex + 1].scoreId,correctFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片this.getCourseScoreActive(this.student[this.userIndex].scoreId,this.userIndex);//   提示保存成功message.success('保存成功');}});} else if (this.imgs[this.imgsIndex].type == 'yx') {updateCourseScoreById({scoreId: this.student[this.userIndex + 1].scoreId,yxCorrectFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片this.getCourseScoreActive(this.student[this.userIndex].scoreId,this.userIndex);//   提示保存成功message.success('保存成功');}});}}, 500);} else if (type == 2) {if (this.userIndex == this.student.length - 1) {message.error('已经是最后一个了');return;}this.userIndex++;// 调用downLoadImage方法得到转换后的图片;this.downLoadImage();setTimeout(() => {// 设置一个变量跟改变了的图片进行拼接let aa = this.imgs;aa[this.imgsIndex].url = this.imgBase64;// 遍历图片的url进行拼接let imgRes = '';if (this.imgs[this.imgsIndex].type == 're') {aa.forEach((item, index) => {if (item.type == 're') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});} else {aa.forEach((item, index) => {if (item.type == 'yx') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});}if (this.imgs[this.imgsIndex].type == 're') {updateCourseScoreById({scoreId: this.student[this.userIndex - 1].scoreId,correctFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片this.getCourseScoreActive(this.student[this.userIndex].scoreId,this.userIndex);//   提示保存成功message.success('保存成功');}});} else if (this.imgs[this.imgsIndex].type == 'yx') {updateCourseScoreById({scoreId: this.student[this.userIndex - 1].scoreId,yxCorrectFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片this.getCourseScoreActive(this.student[this.userIndex].scoreId,this.userIndex);//   提示保存成功message.success('保存成功');}});}}, 500);}},// 点击图片切换背景图changeImg(url, index) {this.imgsIndex = index;this.fabricObj.clear();this.setBackgroundImg(url);},// 获取分数change(value) {console.log(value, 'value');},// formatDate,// 切换图片changeZuo(type) {console.log(11, this.imgsIndex);if (type == 1) {if (this.imgsIndex == 0) {message.error('已经是第一张了');return;} else {// 调用downLoadImage方法得到转换后的图片;this.downLoadImage();setTimeout(() => {// 设置一个变量跟改变了的图片进行拼接let aa = this.imgs;aa[this.imgsIndex + 1].url = this.imgBase64;// 遍历图片的url进行拼接let imgRes = '';if (this.imgs[this.imgsIndex + 1].type == 're') {aa.forEach((item, index) => {if (item.type == 're') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});} else {aa.forEach((item, index) => {if (item.type == 'yx') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});}if (this.imgs[this.imgsIndex + 1].type == 're') {updateCourseScoreById({scoreId: this.scoreId,correctFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片console.log(this.imgs);this.imgs[this.imgsIndex + 1].url = this.imgBase64;//   提示保存成功message.success('保存成功');}});} else if (this.imgs[this.imgsIndex + 1].type == 'yx') {updateCourseScoreById({scoreId: this.scoreId,yxCorrectFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片console.log(this.imgs);this.imgs[this.imgsIndex + 1].url = this.imgBase64;//   提示保存成功message.success('保存成功');}});}}, 500);// 清空页面内容设置背景this.imgsIndex--;this.fabricObj.clear();this.setBackgroundImg(this.imgs[this.imgsIndex].url);}} else if ((type = 2)) {if (this.imgsIndex == this.imgs.length - 1) {message.error('已经是最后一张了');return;}// 调用downLoadImage方法得到转换后的图片;this.downLoadImage();setTimeout(() => {// 设置一个变量跟改变了的图片进行拼接let aa = this.imgs;aa[this.imgsIndex - 1].url = this.imgBase64;let imgRes = '';if (this.imgs[this.imgsIndex - 1].type == 're') {aa.forEach((item, index) => {if (item.type == 're') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});} else {aa.forEach((item, index) => {if (item.type == 'yx') {if (index == 0) {imgRes = item.url;} else {imgRes += ',' + item.url;}}});}if (this.imgs[this.imgsIndex - 1].type == 're') {updateCourseScoreById({scoreId: this.scoreId,correctFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片console.log(this.imgs);this.imgs[this.imgsIndex - 1].url = this.imgBase64;//   提示保存成功message.success('保存成功');}});} else if (this.imgs[this.imgsIndex - 1].type == 'yx') {updateCourseScoreById({scoreId: this.scoreId,yxCorrectFileUrl: imgRes,prepareScore: this.reportData.prepareScore,experimentScore: this.reportData.experimentScore,reportScore: this.reportData.reportScore}).then((res) => {console.log(res, 'res');if (res == '修改成功') {//   给this.imgss替换上一张图片this.imgs[this.imgsIndex - 1].url = this.imgBase64;//   提示保存成功message.success('保存成功');}});}}, 500);// 清空页面内容设置背景this.imgsIndex++;this.fabricObj.clear();this.setBackgroundImg(this.imgs[this.imgsIndex].url);}},changeColors(value) {this.drawColor = value;},changeCuxi(value) {this.drawWidth = value;},onKeyDown(event) {if (event.key >= 'A' && event.key <= 'K') {// 根据按键执行对应的操作switch (event.key) {case 'A':this.selectToolByName('pencil');break;case 'B':this.selectToolByName('duigou1');break;case 'C':this.selectToolByName('cuowu');break;case 'D':this.selectToolByName('line');break;case 'E':this.selectToolByName('arrow');break;case 'F':this.selectToolByName('xuxian');break;case 'G':this.selectToolByName('text');break;case 'H':this.selectToolByName('juxing');break;case 'I':this.selectToolByName('cricle');break;case 'J':this.selectToolByName('ellipse');break;case 'K':this.selectToolByName('equilateral');break;}}},selectToolByName(name) {// 选中指定名称的工具const tool = this.toolsArr.find((tool) => tool.name === name);if (tool) {this.handleTools(tool, this.toolsArr.indexOf(tool));}},changeColor,initCanvas() {console.log(88);console.log(this.imgs, 'this.imgs');setTimeout(() => {this.fabricObj = new fabric.Canvas('canvas', {isDrawingMode: false,selectable: true,selection: true});this.setBackgroundImg(this.imgs[0].url);this.imgsIndex = 0;//绑定画板事件document.addEventListener('keydown', this.onKeyDown);}, 500);},//时间监听fabricObjAddEvent() {this.fabricObj.on({'mouse:down': (o) => {this.mouseFrom.x = o.pointer.x;this.mouseFrom.y = o.pointer.y;this.doDrawing = true;if (this.currentTool == 'text') {this.drawText();}},'mouse:up': (o) => {this.mouseTo.x = o.pointer.x;this.mouseTo.y = o.pointer.y;this.drawingObject = null;this.moveCount = 1;this.doDrawing = false;this.updateModifications(true);},'mouse:move': (o) => {if (this.moveCount % 2 && !this.doDrawing) {//减少绘制频率return;}this.moveCount++;this.mouseTo.x = o.pointer.x;this.mouseTo.y = o.pointer.y;this.drawing();},//对象移动时间'object:moving': (e) => {e.target.opacity = 0.5;},//增加对象'object:added': (e) => {// debugger},'object:modified': (e) => {e.target.opacity = 1;let object = e.target;this.updateModifications(true);},'selection:created': (e) => {console.log(e, 'selection:created');if (e.e.target._objects) {//多选删除var etCount = e.e.target._objects.length;for (var etindex = 0; etindex < etCount; etindex++) {this.fabricObj.remove(e.e.target._objects[etindex]);}} else {//判断是否删除的是imgif (e.selected[0].type == 'image') {return;}this.fabricObj.remove(e.selected[0]);}this.fabricObj.discardActiveObject(); //清楚选中框this.updateModifications(true);}});},//储存历史记录updateModifications(savehistory) {if (savehistory == true) {this.fabricHistoryJson.push(JSON.stringify(this.fabricObj));}},//canvas 历史后退undo() {let state = this.fabricHistoryJson;if (this.mods < state.length) {this.fabricObj.clear().renderAll();this.fabricObj.loadFromJSON(state[state.length - 1 - this.mods - 1]);this.fabricObj.renderAll();this.mods += 1;}},//前进redo() {let state = this.fabricHistoryJson;if (this.mods > 0) {this.fabricObj.clear().renderAll();this.fabricObj.loadFromJSON(state[state.length - 1 - this.mods + 1]);this.fabricObj.renderAll();this.mods -= 1;}},transformMouse(mouseX, mouseY) {return { x: mouseX / this.zoom, y: mouseY / this.zoom };},resetObj() {this.fabricObj.selectable = false;this.fabricObj.selection = false;this.fabricObj.skipTargetFind = true;//清除文字对象if (this.textboxObj) {this.textboxObj.exitEditing();this.textboxObj = null;}},handleTools(tools, idx) {this.initIdx = idx;this.currentTool = tools.name;this.fabricObj.isDrawingMode = false;this.resetObj();switch (tools.name) {case 'pencil':this.fabricObj.isDrawingMode = true;// 设置画笔颜色this.fabricObj.freeDrawingBrush.color = this.drawColor;// 设置画笔宽度this.fabricObj.freeDrawingBrush.width = this.drawWidth;break;case 'remove':this.fabricObj.selection = true;this.fabricObj.skipTargetFind = false;this.fabricObj.selectable = true;break;case 'reset':// 清空页面内容this.fabricObj.clear();this.setBackgroundImg(this.currentImg.src);break;case 'redo':this.redo();break;case 'undo':this.undo();break;default:break;}},setBackgroundImg(imgUrl) {this.currentImg.src = imgUrl;// 重新更新获取最新imgUrl的高度let imgss = new Image();imgss.src = imgUrl;imgss.onload = function () {console.log(imgss.height, imgss.width);};// 重新更新高度setTimeout(() => {// 将图片的宽度设置为750this.fabricObj.setWidth(750);this.fabricObj.setHeight(750 * (imgss.height / imgss.width));let _this = this;_this.fabricObj.setBackgroundImage(this.currentImg.src,_this.fabricObj.renderAll.bind(_this.fabricObj),{ crossOrigin: 'anonymous' });}, 100);},//绘制文字对象drawText() {this.textboxObj = new fabric.Textbox(' ', {left: this.mouseFrom.x,top: this.mouseFrom.y,width: 220,fontSize: 18,fill: this.drawColor,hasControls: true});this.fabricObj.add(this.textboxObj);this.textboxObj.enterEditing();this.textboxObj.hiddenTextarea.focus();this.updateModifications(true);},drawing() {let _this = this;if (this.drawingObject) {this.fabricObj.remove(this.drawingObject);}let fabricObject = null;switch (this.currentTool) {case 'pencil':this.fabricObj.isDrawingMode = true;// 设置画笔颜色this.fabricObj.freeDrawingBrush.color = this.drawColor;// 设置画笔宽度this.fabricObj.freeDrawingBrush.width = this.drawWidth;break;case 'line':fabricObject = new fabric.Line([this.mouseFrom.x,this.mouseFrom.y,this.mouseTo.x,this.mouseTo.y],{stroke: this.drawColor,strokeWidth: this.drawWidth});break;case 'duigou1':fabricObject = new fabric.Path('M2.5 51.5c3 30 8.476 74.5 58 48.5 48-25.2 114.667-75.167 142-97',{left: this.mouseFrom.x,top: this.mouseFrom.y,stroke: this.drawColor,strokeWidth: this.drawWidth,fill: 'transparent' // 或者将这一行完全删除});break;case 'cuowu':fabricObject = new fabric.Path('M1 1L65.5 65.5M66 1L1.5 65.5', {left: this.mouseFrom.x,top: this.mouseFrom.y,stroke: this.drawColor,strokeWidth: this.drawWidth,fill: 'transparent' // 或者将这一行完全删除});break;case 'arrow':fabricObject = new fabric.Path(this.drawArrow(this.mouseFrom.x,this.mouseFrom.y,this.mouseTo.x,this.mouseTo.y,17.5,17.5),{stroke: this.drawColor,fill: 'rgba(255,255,255,0)',strokeWidth: this.drawWidth});break;case 'xuxian': //doshed linefabricObject = new fabric.Line([this.mouseFrom.x,this.mouseFrom.y,this.mouseTo.x,this.mouseTo.y],{strokeDashArray: [10, 3],stroke: this.drawColor,strokeWidth: this.drawWidth});break;case 'juxing': //矩形let path ='M ' +this.mouseFrom.x +' ' +this.mouseFrom.y +' L ' +this.mouseTo.x +' ' +this.mouseFrom.y +' L ' +this.mouseTo.x +' ' +this.mouseTo.y +' L ' +this.mouseFrom.x +' ' +this.mouseTo.y +' L ' +this.mouseFrom.x +' ' +this.mouseFrom.y +' z';fabricObject = new fabric.Path(path, {left: this.mouseFrom.x,top: this.mouseFrom.y,stroke: this.drawColor,strokeWidth: this.drawWidth,fill: 'rgba(255, 255, 255, 0)'});break;case 'cricle': //正圆let radius =Math.sqrt((this.mouseTo.x - this.mouseFrom.x) *(this.mouseTo.x - this.mouseFrom.x) +(this.mouseTo.y - this.mouseFrom.y) *(this.mouseTo.y - this.mouseFrom.y)) / 2;fabricObject = new fabric.Circle({left: this.mouseFrom.x,top: this.mouseFrom.y,stroke: this.drawColor,fill: 'rgba(255, 255, 255, 0)',radius: radius,strokeWidth: this.drawWidth});break;case 'ellipse': //椭圆let left = this.mouseFrom.x;let top = this.mouseFrom.y;let ellipse =Math.sqrt((this.mouseTo.x - left) * (this.mouseTo.x - left) +(this.mouseTo.y - top) * (this.mouseTo.y - top)) / 2;fabricObject = new fabric.Ellipse({left: left,top: top,stroke: this.drawColor,fill: 'rgba(255, 255, 255, 0)',originX: 'center',originY: 'center',rx: Math.abs(left - this.mouseTo.x),ry: Math.abs(top - this.mouseTo.y),strokeWidth: this.drawWidth});break;case 'equilateral': //等边三角形let height = this.mouseTo.y - this.mouseFrom.y;fabricObject = new fabric.Triangle({top: this.mouseFrom.y,left: this.mouseFrom.x,width: Math.sqrt(Math.pow(height, 2) + Math.pow(height / 2.0, 2)),height: height,stroke: this.drawColor,strokeWidth: this.drawWidth,fill: 'rgba(255,255,255,0)'});break;case 'remove':console.log('remove-----');break;default:// statements_def'break;}if (fabricObject) {this.fabricObj.add(fabricObject);this.drawingObject = fabricObject;}},//书写箭头的方法drawArrow(fromX, fromY, toX, toY, theta, headlen) {theta = typeof theta != 'undefined' ? theta : 30;headlen = typeof theta != 'undefined' ? headlen : 10;// 计算各角度和对应的P2,P3坐标let angle = (Math.atan2(fromY - toY, fromX - toX) * 180) / Math.PI,angle1 = ((angle + theta) * Math.PI) / 180,angle2 = ((angle - theta) * Math.PI) / 180,topX = headlen * Math.cos(angle1),topY = headlen * Math.sin(angle1),botX = headlen * Math.cos(angle2),botY = headlen * Math.sin(angle2);let arrowX = fromX - topX,arrowY = fromY - topY;let path = ' M ' + fromX + ' ' + fromY;path += ' L ' + toX + ' ' + toY;arrowX = toX + topX;arrowY = toY + topY;path += ' M ' + arrowX + ' ' + arrowY;path += ' L ' + toX + ' ' + toY;arrowX = toX + botX;arrowY = toY + botY;path += ' L ' + arrowX + ' ' + arrowY;return path;},downLoadImage() {this.done = true;let base64URl = this.fabricObj.toDataURL({formart: 'jpg',multiplier: 1});this.imageBase64 = base64URl;uploadBase64File(base64URl).then((res) => {this.imgBase64 = res.url;});this.done = false;},getStudentScore() {// 获取左侧学生数据this.scoreId = this.data.scoreId;pyStudentScore({ cycleId: this.data.cycleId }).then((res) => {this.student = res;getCourseScore(this.scoreId).then((res) => {this.reportData = res;this.imgs = [];// 判断字符串是否为空,再判断是否有逗号if (res.correctFileUrl) {if (res.correctFileUrl.indexOf(',') > -1) {this.reportFileUrl = res.correctFileUrl.split(',');} else {this.reportFileUrl = [res.correctFileUrl];}} else if (res.reportFileUrl) {if (res.reportFileUrl.indexOf(',') > -1) {this.reportFileUrl = res.reportFileUrl.split(',');} else {this.reportFileUrl = [res.reportFileUrl];}}if (res.yxCorrectFileUrl) {if (res.yxCorrectFileUrl.indexOf(',') > -1) {this.yxReportFileUrl = res.yxCorrectFileUrl.split(',');} else {this.yxReportFileUrl = [res.yxCorrectFileUrl];}} else if (res.yxReportFileUrl) {if (res.yxReportFileUrl.indexOf(',') > -1) {this.yxReportFileUrl = res.yxReportFileUrl.split(',');} else {this.yxReportFileUrl = [res.yxReportFileUrl];}}// 给this.yxReportFileUrl和this.reportFileUrl添加字段yx和re区分this.yxReportFileUrl = this.yxReportFileUrl.map((item) => {return { url: item, type: 'yx' };});this.reportFileUrl = this.reportFileUrl.map((item) => {return { url: item, type: 're' };});this.imgs.push(...this.yxReportFileUrl);this.imgs.push(...this.reportFileUrl);//初始化canvasthis.initCanvas();setTimeout(() => {this.fabricObjAddEvent();}, 500);});});},// 点击切换背景色getCourseScoreActive(scoreId, index) {console.log(22221);this.scoreId = scoreId;this.userIndex = index;getCourseScore(scoreId).then((res) => {this.reportData = res;this.imgs = [];this.yxReportFileUrl = [];this.reportFileUrl = [];// 判断字符串是否为空,再判断是否有逗号if (res.correctFileUrl) {if (res.correctFileUrl.indexOf(',') > -1) {this.reportFileUrl = res.correctFileUrl.split(',');} else {this.reportFileUrl = [res.correctFileUrl];}} else if (res.reportFileUrl) {if (res.reportFileUrl.indexOf(',') > -1) {this.reportFileUrl = res.reportFileUrl.split(',');} else {this.reportFileUrl = [res.reportFileUrl];}}if (res.yxCorrectFileUrl) {if (res.yxCorrectFileUrl.indexOf(',') > -1) {this.yxReportFileUrl = res.yxCorrectFileUrl.split(',');} else {this.yxReportFileUrl = [res.yxCorrectFileUrl];}} else if (res.yxReportFileUrl) {if (res.yxReportFileUrl.indexOf(',') > -1) {this.yxReportFileUrl = res.yxReportFileUrl.split(',');} else {this.yxReportFileUrl = [res.yxReportFileUrl];}}// 给this.yxReportFileUrl和this.reportFileUrl添加字段yx和re区分this.yxReportFileUrl = this.yxReportFileUrl.map((item) => {return { url: item, type: 'yx' };});this.reportFileUrl = this.reportFileUrl.map((item) => {return { url: item, type: 're' };});this.imgs.push(...this.yxReportFileUrl);this.imgs.push(...this.reportFileUrl);this.imgsIndex = 0;console.log(99);//初始化canvasthis.initCanvas();setTimeout(() => {this.fabricObjAddEvent();}, 500);});},goBack() {console.log('返回成绩列表');this.$emit('back', 2);console.log('返回成绩列表');}}};
</script>

遇到的问题,线上链接的图片跨域了 

解决办法,设置图片的时候处理跨域

  setBackgroundImg(imgUrl) {this.currentImg.src = imgUrl;// 重新更新获取最新imgUrl的高度let imgss = new Image();imgss.src = imgUrl;imgss.onload = function () {console.log(imgss.height, imgss.width);};// 重新更新高度setTimeout(() => {// 将图片的宽度设置为750this.fabricObj.setWidth(750);this.fabricObj.setHeight(750 * (imgss.height / imgss.width));let _this = this;_this.fabricObj.setBackgroundImage(this.currentImg.src,_this.fabricObj.renderAll.bind(_this.fabricObj),{ crossOrigin: 'anonymous' }   // 处理跨域);}, 100);},

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.bcls.cn/rvMO/10178.shtml

如若内容造成侵权/违法违规/事实不符,请联系编程老四网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

C++之数组

1&#xff0c;概述 所谓数组&#xff0c;就是一个集合&#xff0c;里面存放了相同类型的数据元素 特点1&#xff1a;数组中没干过数据元素都是相同的数据类型 特点2&#xff1a;数组都是连续存放位置组成的 2&#xff0c;一维数组 2.1 一维数组的定义 一维数组定义有三种…

杭电OJ 2018 母牛的故事 C++

思路&#xff1a;有点像是斐波那契数列 #include <iostream> #include <vector> using namespace std; int main() { int n; vector<int> num(56); num[1] 1; num[2] 2; num[3] 3; num[4] 4; for (int i 5; i < num.size(); i) { …

MySQL:错误ERROR 1045 (28000)详解

1.问题说明 有时候我们登录Mysql输入密码的时候&#xff0c;会出现这种情况&#xff1a; mysql -u root -p Enter Password > ‘密码’ 错误&#xff1a;ERROR 1045 (28000): Access denied for user ‘root’‘localhost’ (using password: YES) 或者&#xff1a;错误…

VR元宇宙的概念|VR体验店加盟|虚拟现实设备销售

VR元宇宙是一个结合了虚拟现实&#xff08;Virtual Reality&#xff09;和增强现实&#xff08;Augmented Reality&#xff09;等技术的概念&#xff0c;代表着一个虚拟的多维度世界。它是一个由数字化的空间构成的虚拟环境&#xff0c;可以通过虚拟现实设备进行交互和探索。 元…

数据结构从入门到精通——算法的时间复杂度和空间复杂度

算法的时间复杂度和空间复杂度 前言一、算法效率1.1 如何衡量一个算法的好坏1.2 算法的复杂度 二、时间复杂度2.1 时间复杂度的概念2.2 大O的渐进表示法2.3常见时间复杂度计算举例2.4等差数列计算公式2.5等比数列计算方法 三、空间复杂度四、 常见复杂度对比五、 复杂度的oj练习…

RabbitMQ安装

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 RabbitMQ安装下载安装Rabbitmq-server RabbitMQ安装 下载 官…

Ansible stat模块 stat模块 – 检索文件或文件系统状态

目录 语法判断一个不存在的文件 stat模块 – 检索文件或文件系统状态 语法 这里查看/tmp/index.html 这个文件在不 ansible slave -m stat -a path/tmp/index.html判断一个不存在的文件 ansible slave -m stat -a path/tmp/index111.html返回false 说明文件不存在 本章结束…

4.5.CVAT——视频标注的详细步骤

文章目录 1. 跟踪模式&#xff08;基础&#xff09;2. 跟踪模式&#xff08;高级&#xff09;3. 带多边形的轨迹模式 追踪模式Track mode &#xff08;视频标注使用&#xff09;——类似pr的动画效果 1. 跟踪模式&#xff08;基础&#xff09; 使用示例&#xff1a; 为一系列…

继电器测试中需要注意的安全事项有哪些?

继电器广泛应用于电气控制系统中的开关元件&#xff0c;其主要功能是在输入信号的控制下实现输出电路的断开或闭合。在继电器测试过程中&#xff0c;为了确保测试的准确性和安全性&#xff0c;需要遵循一定的安全事项。以下是在进行继电器测试时需要注意的安全事项&#xff1a;…

作业1-224——P1331 海战

思路 深搜的方式&#xff0c;让它只遍历矩形块&#xff0c;然后在下面的遍历中判断是否出现矩形块交叉&#xff0c;但是很难实现&#xff0c;然后发现可以通过在遍历过程中判断是否合法。 参考代码 #include<iostream> #include<cstdio> using namespace std; …

php 支持mssqlserver

系统不支持:sqlsrv 需要一下几个环节 1.准备检测php版本 查看 VC 版本 查看操作系统位数&#xff1a;X86(32位) 和X64 2.下载php的sqlserver库 extensionphp_sqlsrv_74_nts_x64.dll extensionphp_pdo_sqlsrv_74_nts_x64.dll extensionphp_sqlsrv_74_nts_x64 extensionphp_…

《C++进阶--10.多态》

目录 10. 多态 10.1 多态的基本概念 10.2 多态案例一-计算器类 10.3 纯虚函数和抽象类 10.4 多态案例二-制作饮品 10.5 虚析构和纯虚析构 10.6 多态案例三-电脑组装 10. 多态 10.1 多态的基本概念 多态是C面向对象三大特性之一 多态分为两类 静态多态: 函数重载 和 运算…

规范 Git 提交说明

Commit Message 的规范 Commit Message 的规范主要包括以下几个部分&#xff1a; Header&#xff1a;包括三个字段&#xff0c;分别是 type&#xff08;必需&#xff0c;用于说明 commit 的类别&#xff09;、scope&#xff08;必需&#xff0c;说明 commit 影响的范围&#…

高性能的key-value数据库Redis 介绍

Redis 是一个高性能的key-value数据库。 Redis是一个开源的键值存储系统&#xff0c;通常用于缓存和消息传递。它支持多种类型的数据结构&#xff0c;如字符串、列表、集合、散列表和有序集合等。Redis的特点是提供了高性能、灵活性和可伸缩性。 Redis的主要特点包括&#xff…

【嵌入式学习】网络编程day0229

一、思维导图 二、练习 TCP通信 服务器 #include <myhead.h> #define SER_IP "192.168.126.42" #define SER_PORT 8888 int main(int argc, const char *argv[]) {int wfd-1;//创建套接字if((wfdsocket(AF_INET,SOCK_STREAM,0))-1){perror("error"…

代码随想录Leetcode139. 单词拆分

题目&#xff1a; 代码(首刷看解析 2024年2月28日&#xff09;&#xff1a; class Solution { public:// 动态规划bool wordBreak(string s, vector<string>& wordDict) {int n s.size();// 初始化dp[i]vector<int> dp(n 1, false);dp[0] true;// 遍历 排列…

Linux——进程控制(一)进程的创建与退出

目录 一、进程创建 1.写时拷贝 2.创建多个进程 二、进程终止 1.main函数的返回值 2.bash中的$? 3.自定义退出码 4.C语言的错误码 5.错误码与退出码的区别 6.代码异常终止 7.exit函数 8.总结 一、进程创建 在之前&#xff0c;我们学过linux中的非常重要的函数——…

【网站项目】328学生就业管理系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

c++面试2

一 、 char类型数组转换成字符串的方法 使用 std::string 构造函数: 可以使用 std::string 类的构造函数直接将 C 风格字符串转换为 std::string 对象&#xff0c;例如&#xff1a;std::string str(buf);。 const char* buf "Hello, world!"; // C 风格字符串 std::…

WPF 滑动条样式

效果图&#xff1a; 浅色&#xff1a; 深色&#xff1a; 滑动条部分代码&#xff1a; <Style x:Key"RepeatButtonTransparent" TargetType"{x:Type RepeatButton}"><Setter Property"OverridesDefaultStyle" Value"true"/&g…
推荐文章