这个功能主要实现批阅的,修改上传的图片,标记内容
看看效果图
主要是根据fabric这个库来进行完成的
下载包
npm i fabric
组件内注册使用
import { fabric } from 'fabric';
步骤
body中
<div
v-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">
<div
style="background: #f2f4f8; height: 100%; width: 100%; padding: 10px"
>
<div
><color-picker @changeColor="changeColors" @changeCuxi="changeCuxi" // 使用的颜色库
/></div>
<a-divider
dashed
style="border-color: rgb(204, 204, 204); margin-top: 10px"
/>
<div style="margin: 10px 0">
<div>预习报告</div>
<div>
<template v-for="(item, index) in yxReportFileUrl">
<img
class="reportImg"
:src="item.url"
@click="changeImg(item.url, index)"
/>
</template>
</div>
</div>
<a-divider
dashed
style="border-color: rgb(204, 204, 204); margin-top: 10px"
/>
<div style="margin: 10px 0">
<div>实操作及课后报告</div>
<div>
<template v-for="(item, index) in reportFileUrl">
<img
class="reportImg"
:src="item.url"
@click="changeImg(item.url, yxReportFileUrl.length - 1 + index)"
/>
</template>
</div>
</div>
<a-divider
dashed
style="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-input
v-model:value="reportData.prepareScore"
placeholder="请输入"
style="width: 300px"
/>
</div>
</div>
<a-divider
dashed
style="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-input
v-model:value="reportData.experimentScore"
placeholder="请输入"
style="width: 300px"
/>
</div>
</div>
<a-divider
dashed
style="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-input
v-model:value="reportData.reportScore"
placeholder="请输入"
style="width: 300px"
/>
</div>
</div>
<a-divider
dashed
style="border-color: rgb(204, 204, 204); margin-top: 10px"
/>
<!-- 三个按钮,上一个,下一个,返回课程列表页-->
<div style="margin: 30px 0">
<a-button
style="background: #2d8cf0; color: #fff; border-radius: 6px"
@click="changeUser(1)"
>上一个</a-button
>
<a-button
style="
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 },
// 获取props
props: ['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 {
//判断是否删除的是img
if (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(() => {
// 将图片的宽度设置为750
this.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 line
fabricObject = 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);
//初始化canvas
this.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);
//初始化canvas
this.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(() => {
// 将图片的宽度设置为750
this.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);
},