目录
0. 前言
1. 安装fabric与引入
2. fabric组件的使用
3. 属性相关设置
4. 初始化加载
4. 方法
5. 全代码
0. 前言
利用fabric组件,实现图片上传、图片”裁剪“、自定义的区域标记一系列操作
先放一张效果图吧👇
1. 安装fabric与引入
npm i fabric -S
我用的是全局引入方式,视情况调整
import fabric from 'fabric';
Vue.use(fabric);
先放一个fabric.js API地址☞Api | Fabric中文文档 (gitee.io)
2. fabric组件的使用
定义容器id=canvas,注意宽高
<div class="maintenancePlanAdd"><div class="panel-body"><div class="demo"><canvas id="canvas" :width="width" :height="height" /><div class="draw-btn-group" v-show="!readstate"><div><el-button class="el-icon-upload" size="mini" type="primary"style="width: 80px !important;" @click="uploadImgConfirm">图片上传</el-button><el-button size="mini" type="danger" icon="el-icon-delete" @click="clean">清除</el-button></div><div><el-buttonv-show="bgImgSrc !== ''"v-for="(item, index) in alarmLevel":key="index":style="{background:colorGrounp[index]}"size="mini"@click="drawPolygon(index)">{{ item }}</el-button></div></div></div></div><img id="expImg" :src="bgImgSrc"><img id="img" :src="bgImgSrc"><input v-show="false" type="file" @change="uploadImgChange" id="imgInput" accept="image/*"><p class="tip-title" v-show="bgImgSrc === ''">上传的图片可以进行拖拽调整大小和方向</p></div>
3. 属性相关设置
累了,不想写了
data() {return {bgImgFlag: true,bgImgSrc: '',imgFile: {},width: 800,height: 400,alarmLevel: ['一级风险', '二级风险', '三级风险', '四级风险'],colorGrounp: ['rgba(51, 164, 255, 1)', 'rgba(255, 200, 89, 1)', 'rgba(255, 160, 89, 1)', 'rgba(196,43, 1, 1)'],colorGrounpFill: ['rgba(51, 164, 255, 0.3)', 'rgba(255, 200, 89, 0.3)', 'rgba(255, 160, 89, 0.3)', 'rgba(196,43, 1, 0.3)'],canvas: {},mouseFrom: {},mouseTo: {},drawType: '', // 当前绘制图像ROIdrawWidth: 2, // 笔触宽度drawingObject: null, // 当前绘制对象moveCount: 1, // 绘制移动计数器doDrawing: false, // 绘制状态// polygon 相关参数polygonMode: false,pointArray: [],lineArray: [],savePointsGroup: [],activeShape: false,activeLine: '',line: {},deleteIconURL: require('@/assets/screen/icon-close.png') // 区域标记取消的x号图标};},
4. 初始化加载
this.canvas = new fabric.Canvas('canvas', {skipTargetFind: false, // 当为真时,跳过目标检测。目标检测将返回始终未定义。点击选择将无效selectable: false, // 为false时,不能选择对象进行修改selection: false // 是否可以多个对象为一组});this.canvas.selectionColor = 'rgba(0,0,0,0.05)';this.canvas.on('mouse:down', this.mousedown);this.canvas.on('mouse:move', this.mousemove);document.onkeydown = e => {// 键盘 delect删除所选元素if (e.keyCode == 46) {this.deleteObj();}// ctrl+z 删除最近添加的元素if (e.keyCode == 90 && e.ctrlKey) {this.canvas.remove(this.canvas.getObjects()[this.canvas.getObjects().length - 1]);}};this.$nextTick(() => {this.loadDraw(); // 回显之前标注过的内容,底图和区域标记内容});
4. 方法
methods: {// 保存当前画布为png图片save() {var canvas = document.getElementById('canvas');var imgData = canvas.toDataURL('png');imgData = imgData.replace('image/png', 'image/octet-stream');// 下载后的问题名,可自由指定var filename = 'drawingboard_' + (new Date()).getTime() + '.' + 'png';this.saveFile(imgData, filename);},saveFile(data, filename) {var save_link = document.createElement('a');save_link.href = data;save_link.download = filename;var event = document.createEvent('MouseEvents');event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);save_link.dispatchEvent(event);},// 提交绘制内容submitDraw() {const params = {pointInfo: [],imgInfo: '',img: ''};this.canvas.toJSON(['alarmLevel', 'isBgImg']).objects.forEach(item => {const element = {alarmLevel: item.alarmLevel,pointInfo: ''};if (item?.points) {element.pointInfo = item.points;params.pointInfo.push(element);}if (item?.isBgImg) {params.imgInfo = item;params.img = item.src;delete params.imgInfo.src;}});this.$emit('saveDraw', params);},// 清除画布clean() {this.$confirm('是否清除图片和标记?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.canvas.clear();this.bgImgSrc = '';this.bgImgFlag = true;});},// 从已渲染的DOM元素加载图片至canvasloadExpImg() {const imgElement = document.getElementById('expImg');imgElement.onload = () => {// eslint-disable-next-line new-capnew fabric.Image.fromURL(imgElement.src,img => {img.scale(0.3);img.set({originX: 'center',originY: 'center'}, { crossOrigin: 'anonymous' });img.on('scaling', e => { // 拉伸事件const h = img.scaleY;const w = img.scaleX;if (h !== w || w == h) { // 判断缩放值相等或不相等后执行图片等比缩放if (e.e.movementY == -1 || e.e.movementY == 1) {img.scale(h);// 缩放} else {img.scale(w);}}});img.setCoords();img.centeredScaling = true;img.centerTransform = true;this.canvas.add(img);this.canvas.centerObject(img);this.canvas.renderAll();}, {selectable: true,hasControls: true,centeredScaling: false,zIndex: -99,isBgImg: true});};},// 上传确认uploadImgConfirm() {if (this.bgImgSrc !== '') {this.$confirm('是否重新上传标记?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.canvas.clear();this.bgImgFlag = true;document.getElementById('imgInput').click();});} else {document.getElementById('imgInput').click();}},// 从文件加载图片至canvasuploadImgChange() {// 获取文件var eleImportInput = document.getElementById('imgInput');this.imgFile = eleImportInput.files[0];var imgTitle = '';// 从reader中获取选择文件的srcif (/\.(jpe?g|png|gif)$/i.test(this.imgFile.name)) {var reader = new FileReader();var _this = this;reader.addEventListener('load',function() {imgTitle = _this.imgFile.name;_this.bgImgSrc = this.result;},false);reader.readAsDataURL(this.imgFile);}this.loadExpImg();},// 鼠标按下时触发mousedown(e) {if (undefined === e) return;// 记录鼠标按下时的坐标var xy = e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY);this.mouseFrom.x = xy.x;this.mouseFrom.y = xy.y;this.doDrawing = true;this.canvas.skipTargetFind = false;try {// 此段为判断是否闭合多边形,点击红点时闭合多边形if (this.pointArray.length > 1) {// e.target.id == this.pointArray[0].id 表示点击了初始红点if (e.target && e.target.id == this.pointArray[0].id) {this.generatePolygon();return;}}// 未点击红点则继续作画if (this.polygonMode && this.pointArray.length < 4) {this.addPoint(e);} else if (this.polygonMode && this.pointArray.length > 0) {this.$message.warning('最多设置四个点');}} catch (error) {console.log(error);}},// 鼠标松开执行mouseup(e) {if (undefined === e) return;var xy = e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY);this.mouseTo.x = xy.x;this.mouseTo.y = xy.y;this.drawingObject = null;this.moveCount = 1;},// 鼠标移动过程中已经完成了绘制mousemove(e) {if (undefined === e) return;if (this.moveCount % 2 && !this.doDrawing) {// 减少绘制频率return;}this.moveCount++;var xy = e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY);this.mouseTo.x = xy.x;this.mouseTo.y = xy.y;if (this.activeLine && this.activeLine.class == 'line') {var pointer = this.canvas.getPointer(e.e);this.activeLine.set({x2: pointer.x,y2: pointer.y});var points = this.activeShape.get('points');points[this.pointArray.length] = {x: pointer.x,y: pointer.y,zIndex: 1};this.activeShape.set({points: points});this.canvas.renderAll();}this.canvas.renderAll();},deleteObj() {this.canvas.getActiveObjects().map(item => {this.canvas.remove(item);});},transformMouse(mouseX, mouseY) {return {x: mouseX / 1,y: mouseY / 1};},// 绘制多边形开始drawPolygon(data) {if (this.bgImgFlag) {this.canvas.getObjects().forEach(obj => {if (obj.isBgImg) {obj.hasControls = false;obj.selectable = false;obj.evented = false;}});this.bgImgFlag = false;this.canvas.renderAll();}this.drawType = data;this.polygonMode = true;this.pointArray = []; // 顶点集合this.lineArray = []; // 线集合this.canvas.isDrawingMode = false;},addPoint(e) {var random = Math.floor(Math.random() * 10000);var id = new Date().getTime() + random;var circle = new fabric.Circle({radius: 5,fill: '#ffffff',stroke: '#333333',strokeWidth: 0.5,left: (e.pointer.x || e.e.layerX) / this.canvas.getZoom(),top: (e.pointer.y || e.e.layerY) / this.canvas.getZoom(),selectable: false,hasBorders: false,hasControls: false,originX: 'center',originY: 'center',id: id,objectCaching: false});if (this.pointArray.length == 0) {circle.set({fill: this.colorGrounp[this.drawType]});}var points = [(e.pointer.x || e.e.layerX) / this.canvas.getZoom(),(e.pointer.y || e.e.layerY) / this.canvas.getZoom(),(e.pointer.x || e.e.layerX) / this.canvas.getZoom(),(e.pointer.y || e.e.layerY) / this.canvas.getZoom()];this.line = new fabric.Line(points, {strokeWidth: 2,fill: this.colorGrounp[this.drawType],stroke: this.colorGrounp[this.drawType],class: 'line',originX: 'center',originY: 'center',selectable: false,hasBorders: false,hasControls: false,evented: false,objectCaching: false});if (this.activeShape) {var pos = this.canvas.getPointer(e.e);var points = this.activeShape.get('points');points.push({x: pos.x,y: pos.y});var polygon = new fabric.Polygon(points, {stroke: '#333333',strokeWidth: 1,fill: this.colorGrounpFill[this.drawType],opacity: 0.3,selectable: false,hasBorders: false,hasControls: false,evented: false,objectCaching: false});this.canvas.remove(this.activeShape);this.canvas.add(polygon);this.activeShape = polygon;this.canvas.renderAll();} else {var polyPoint = [{x: (e.pointer.x || e.e.layerX) / this.canvas.getZoom(),y: (e.pointer.y || e.e.layerY) / this.canvas.getZoom()}];var polygon = new fabric.Polygon(polyPoint, {stroke: '#333333',strokeWidth: 1,fill: '#cccccc',opacity: 0.3,selectable: false,hasBorders: false,hasControls: false,evented: false,objectCaching: false});this.activeShape = polygon;this.canvas.add(polygon);}this.activeLine = this.line;this.pointArray.push(circle);this.lineArray.push(this.line);this.canvas.add(this.line);this.canvas.add(circle);},generatePolygon() {var points = [];this.pointArray.map((point, index) => {points.push({x: point.left,y: point.top});this.canvas.remove(point);});this.lineArray.map((line, index) => {this.canvas.remove(line);});this.canvas.remove(this.activeShape).remove(this.activeLine);var polygon = new fabric.Polygon(points, {stroke: this.colorGrounp[this.drawType],strokeWidth: this.drawWidth,fill: this.colorGrounpFill[this.drawType],opacity: 1,selectable: false,hasBorders: false,hasControls: false,alarmLevel: this.drawType});let max = 0;for (let i = 1; i < this.canvas._objects.length; i++) {if (this.canvas._objects[i].index > max) max = this.canvas._objects[i].index;}polygon.index = max + 1;this.canvas.add(polygon);this.activeLine = null;this.activeShape = null;this.polygonMode = false;this.doDrawing = false;// this.drawType = null;fabric.Image.fromURL(this.deleteIconURL, this.deletecallback);},// 从画布中删除当前选中的对象deleteObject() {const activeObject = this.canvas.getActiveObject();if (activeObject) {this.canvas._objects.forEach(item => {if (item.index === activeObject.index) {this.canvas.remove(item);}});this.canvas.remove(activeObject);this.canvas.renderAll();}},// 渲染删除按钮async deletecallback(img) {const self = this;let max = 0;for (let i = 1; i < this.canvas._objects.length; i++) {if (this.canvas._objects[i].index > max) max = this.canvas._objects[i].index;}img.index = max;const oImg = await img.set({left: this.pointArray[0].left - 20,top: this.pointArray[0].top - 20,width: 40,height: 40,angle: 0}).scale(0.8);this.canvas.add(oImg).renderAll();this.canvas.setActiveObject(oImg);oImg.on('mousedown', function() {self.deleteObject();});},// 回显详情信息loadDraw() {const self = this;if (self.drawinfo.id === '') return;const pointGroup = JSON.parse(self.drawinfo.pointInfo);const imgInfo = JSON.parse(self.drawinfo.imgInfo);self.bgImgSrc = self.drawinfo.img;imgInfo.src = self.drawinfo.img;// 1、加载底图fabric.util.enlivenObjects([imgInfo], objects => {objects.forEach(o => {o.selectable = false;o.hasControls = false;o.centeredScaling = false;this.canvas.add(o);});// 2、处理多边形绘制回显操作pointGroup.forEach(async (item, index) => {if (item.pointInfo !== '') {const polygon = new fabric.Polygon(item.pointInfo, {stroke: self.colorGrounp[item.alarmLevel],strokeWidth: self.drawWidth,fill: self.colorGrounpFill[item.alarmLevel],opacity: 1,selectable: false,hasBorders: false,hasControls: false,alarmLevel: item.alarmLevel});polygon.index = index;self.canvas.add(polygon);self.activeLine = null;self.activeShape = null;self.polygonMode = false;self.doDrawing = false;if (!self.readstate) {fabric.Image.fromURL(self.deleteIconURL, async img => {const _self = this;img.index = index;const oImg = await img.set({left: item.pointInfo[0].x - 20,top: item.pointInfo[0].y - 20,width: 40,height: 40,angle: 0}).scale(0.8);this.canvas.add(oImg);oImg.on('mousedown', function() {_self.deleteObject();});});}}});});self.canvas.renderAll();}}
5. 全代码
累了累了,开始摆烂,以后再调整,直接放全代码吧
<template><div class="maintenancePlanAdd"><div class="panel-body"><div class="demo"><canvas id="canvas" :width="width" :height="height" /><div class="draw-btn-group" v-show="!readstate"><div><el-button class="el-icon-upload" size="mini" type="primary"style="width: 80px !important;" @click="uploadImgConfirm">图片上传</el-button><el-button size="mini" type="danger" icon="el-icon-delete" @click="clean">清除</el-button></div><div><el-buttonv-show="bgImgSrc !== ''"v-for="(item, index) in alarmLevel":key="index":style="{background:colorGrounp[index]}"size="mini"@click="drawPolygon(index)">{{ item }}</el-button></div></div></div></div><img id="expImg" :src="bgImgSrc"><img id="img" :src="bgImgSrc"><input v-show="false" type="file" @change="uploadImgChange" id="imgInput" accept="image/*"><p class="tip-title" v-show="bgImgSrc === ''">上传的图片可以进行拖拽调整大小和方向</p></div>
</template>
<script>
export default {props: ['readstate', 'drawinfo'],data() {return {bgImgFlag: true,bgImgSrc: '',imgFile: {},width: 800,height: 400,alarmLevel: ['一级风险', '二级风险', '三级风险', '四级风险'],colorGrounp: ['rgba(51, 164, 255, 1)', 'rgba(255, 200, 89, 1)', 'rgba(255, 160, 89, 1)', 'rgba(196,43, 1, 1)'],colorGrounpFill: ['rgba(51, 164, 255, 0.3)', 'rgba(255, 200, 89, 0.3)', 'rgba(255, 160, 89, 0.3)', 'rgba(196,43, 1, 0.3)'],canvas: {},mouseFrom: {},mouseTo: {},drawType: '', // 当前绘制图像ROIdrawWidth: 2, // 笔触宽度drawingObject: null, // 当前绘制对象moveCount: 1, // 绘制移动计数器doDrawing: false, // 绘制状态// polygon 相关参数polygonMode: false,pointArray: [],lineArray: [],savePointsGroup: [],activeShape: false,activeLine: '',line: {},deleteIconURL: require('@/assets/screen/icon-close.png')};},watch: {drawinfo: {handler(n) {this.drawinfo = n;this.$nextTick(() => {this.loadDraw();});},deep: true},readstate: {handler(n) {this.readstate = n;},deep: true},width() {this.canvas.setWidth(this.width);},height() {this.canvas.setHeight(this.height);}},mounted() {this.canvas = new fabric.Canvas('canvas', {skipTargetFind: false, // 当为真时,跳过目标检测。目标检测将返回始终未定义。点击选择将无效selectable: false, // 为false时,不能选择对象进行修改selection: false // 是否可以多个对象为一组});this.canvas.selectionColor = 'rgba(0,0,0,0.05)';this.canvas.on('mouse:down', this.mousedown);this.canvas.on('mouse:move', this.mousemove);document.onkeydown = e => {// 键盘 delect删除所选元素if (e.keyCode == 46) {this.deleteObj();}// ctrl+z 删除最近添加的元素if (e.keyCode == 90 && e.ctrlKey) {this.canvas.remove(this.canvas.getObjects()[this.canvas.getObjects().length - 1]);}};this.$nextTick(() => {this.loadDraw();});},methods: {// 保存当前画布为png图片save() {var canvas = document.getElementById('canvas');var imgData = canvas.toDataURL('png');imgData = imgData.replace('image/png', 'image/octet-stream');// 下载后的问题名,可自由指定var filename = 'drawingboard_' + (new Date()).getTime() + '.' + 'png';this.saveFile(imgData, filename);},saveFile(data, filename) {var save_link = document.createElement('a');save_link.href = data;save_link.download = filename;var event = document.createEvent('MouseEvents');event.initMouseEvent('click', true, false, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);save_link.dispatchEvent(event);},// 提交绘制内容submitDraw() {const params = {pointInfo: [],imgInfo: '',img: ''};this.canvas.toJSON(['alarmLevel', 'isBgImg']).objects.forEach(item => {const element = {alarmLevel: item.alarmLevel,pointInfo: ''};if (item?.points) {element.pointInfo = item.points;params.pointInfo.push(element);}if (item?.isBgImg) {params.imgInfo = item;params.img = item.src;delete params.imgInfo.src;}});this.$emit('saveDraw', params);},// 清除画布clean() {this.$confirm('是否清除图片和标记?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.canvas.clear();this.bgImgSrc = '';this.bgImgFlag = true;});},// 从已渲染的DOM元素加载图片至canvasloadExpImg() {const imgElement = document.getElementById('expImg');imgElement.onload = () => {// eslint-disable-next-line new-capnew fabric.Image.fromURL(imgElement.src,img => {img.scale(0.3);img.set({originX: 'center',originY: 'center'}, { crossOrigin: 'anonymous' });img.on('scaling', e => { // 拉伸事件const h = img.scaleY;const w = img.scaleX;if (h !== w || w == h) { // 判断缩放值相等或不相等后执行图片等比缩放if (e.e.movementY == -1 || e.e.movementY == 1) {img.scale(h);// 缩放} else {img.scale(w);}}});img.setCoords();img.centeredScaling = true;img.centerTransform = true;this.canvas.add(img);this.canvas.centerObject(img);this.canvas.renderAll();}, {selectable: true,hasControls: true,centeredScaling: false,zIndex: -99,isBgImg: true});};},// 上传确认uploadImgConfirm() {if (this.bgImgSrc !== '') {this.$confirm('是否重新上传标记?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.canvas.clear();this.bgImgFlag = true;document.getElementById('imgInput').click();});} else {document.getElementById('imgInput').click();}},// 从文件加载图片至canvasuploadImgChange() {// 获取文件var eleImportInput = document.getElementById('imgInput');this.imgFile = eleImportInput.files[0];var imgTitle = '';// 从reader中获取选择文件的srcif (/\.(jpe?g|png|gif)$/i.test(this.imgFile.name)) {var reader = new FileReader();var _this = this;reader.addEventListener('load',function() {imgTitle = _this.imgFile.name;_this.bgImgSrc = this.result;},false);reader.readAsDataURL(this.imgFile);}this.loadExpImg();},// 鼠标按下时触发mousedown(e) {if (undefined === e) return;// 记录鼠标按下时的坐标var xy = e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY);this.mouseFrom.x = xy.x;this.mouseFrom.y = xy.y;this.doDrawing = true;this.canvas.skipTargetFind = false;try {// 此段为判断是否闭合多边形,点击红点时闭合多边形if (this.pointArray.length > 1) {// e.target.id == this.pointArray[0].id 表示点击了初始红点if (e.target && e.target.id == this.pointArray[0].id) {this.generatePolygon();return;}}// 未点击红点则继续作画if (this.polygonMode && this.pointArray.length < 4) {this.addPoint(e);} else if (this.polygonMode && this.pointArray.length > 0) {this.$message.warning('最多设置四个点');}} catch (error) {console.log(error);}},// 鼠标松开执行mouseup(e) {if (undefined === e) return;var xy = e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY);this.mouseTo.x = xy.x;this.mouseTo.y = xy.y;this.drawingObject = null;this.moveCount = 1;},// 鼠标移动过程中已经完成了绘制mousemove(e) {if (undefined === e) return;if (this.moveCount % 2 && !this.doDrawing) {// 减少绘制频率return;}this.moveCount++;var xy = e.pointer || this.transformMouse(e.e.offsetX, e.e.offsetY);this.mouseTo.x = xy.x;this.mouseTo.y = xy.y;if (this.activeLine && this.activeLine.class == 'line') {var pointer = this.canvas.getPointer(e.e);this.activeLine.set({x2: pointer.x,y2: pointer.y});var points = this.activeShape.get('points');points[this.pointArray.length] = {x: pointer.x,y: pointer.y,zIndex: 1};this.activeShape.set({points: points});this.canvas.renderAll();}this.canvas.renderAll();},deleteObj() {this.canvas.getActiveObjects().map(item => {this.canvas.remove(item);});},transformMouse(mouseX, mouseY) {return {x: mouseX / 1,y: mouseY / 1};},// 绘制多边形开始drawPolygon(data) {if (this.bgImgFlag) {this.canvas.getObjects().forEach(obj => {if (obj.isBgImg) {obj.hasControls = false;obj.selectable = false;obj.evented = false;}});this.bgImgFlag = false;this.canvas.renderAll();}this.drawType = data;this.polygonMode = true;this.pointArray = []; // 顶点集合this.lineArray = []; // 线集合this.canvas.isDrawingMode = false;},addPoint(e) {var random = Math.floor(Math.random() * 10000);var id = new Date().getTime() + random;var circle = new fabric.Circle({radius: 5,fill: '#ffffff',stroke: '#333333',strokeWidth: 0.5,left: (e.pointer.x || e.e.layerX) / this.canvas.getZoom(),top: (e.pointer.y || e.e.layerY) / this.canvas.getZoom(),selectable: false,hasBorders: false,hasControls: false,originX: 'center',originY: 'center',id: id,objectCaching: false});if (this.pointArray.length == 0) {circle.set({fill: this.colorGrounp[this.drawType]});}var points = [(e.pointer.x || e.e.layerX) / this.canvas.getZoom(),(e.pointer.y || e.e.layerY) / this.canvas.getZoom(),(e.pointer.x || e.e.layerX) / this.canvas.getZoom(),(e.pointer.y || e.e.layerY) / this.canvas.getZoom()];this.line = new fabric.Line(points, {strokeWidth: 2,fill: this.colorGrounp[this.drawType],stroke: this.colorGrounp[this.drawType],class: 'line',originX: 'center',originY: 'center',selectable: false,hasBorders: false,hasControls: false,evented: false,objectCaching: false});if (this.activeShape) {var pos = this.canvas.getPointer(e.e);var points = this.activeShape.get('points');points.push({x: pos.x,y: pos.y});var polygon = new fabric.Polygon(points, {stroke: '#333333',strokeWidth: 1,fill: this.colorGrounpFill[this.drawType],opacity: 0.3,selectable: false,hasBorders: false,hasControls: false,evented: false,objectCaching: false});this.canvas.remove(this.activeShape);this.canvas.add(polygon);this.activeShape = polygon;this.canvas.renderAll();} else {var polyPoint = [{x: (e.pointer.x || e.e.layerX) / this.canvas.getZoom(),y: (e.pointer.y || e.e.layerY) / this.canvas.getZoom()}];var polygon = new fabric.Polygon(polyPoint, {stroke: '#333333',strokeWidth: 1,fill: '#cccccc',opacity: 0.3,selectable: false,hasBorders: false,hasControls: false,evented: false,objectCaching: false});this.activeShape = polygon;this.canvas.add(polygon);}this.activeLine = this.line;this.pointArray.push(circle);this.lineArray.push(this.line);this.canvas.add(this.line);this.canvas.add(circle);},generatePolygon() {var points = [];this.pointArray.map((point, index) => {points.push({x: point.left,y: point.top});this.canvas.remove(point);});this.lineArray.map((line, index) => {this.canvas.remove(line);});this.canvas.remove(this.activeShape).remove(this.activeLine);var polygon = new fabric.Polygon(points, {stroke: this.colorGrounp[this.drawType],strokeWidth: this.drawWidth,fill: this.colorGrounpFill[this.drawType],opacity: 1,selectable: false,hasBorders: false,hasControls: false,alarmLevel: this.drawType});let max = 0;for (let i = 1; i < this.canvas._objects.length; i++) {if (this.canvas._objects[i].index > max) max = this.canvas._objects[i].index;}polygon.index = max + 1;this.canvas.add(polygon);this.activeLine = null;this.activeShape = null;this.polygonMode = false;this.doDrawing = false;// this.drawType = null;fabric.Image.fromURL(this.deleteIconURL, this.deletecallback);},// 从画布中删除当前选中的对象deleteObject() {const activeObject = this.canvas.getActiveObject();if (activeObject) {this.canvas._objects.forEach(item => {if (item.index === activeObject.index) {this.canvas.remove(item);}});this.canvas.remove(activeObject);this.canvas.renderAll();}},// 渲染删除按钮async deletecallback(img) {const self = this;let max = 0;for (let i = 1; i < this.canvas._objects.length; i++) {if (this.canvas._objects[i].index > max) max = this.canvas._objects[i].index;}img.index = max;const oImg = await img.set({left: this.pointArray[0].left - 20,top: this.pointArray[0].top - 20,width: 40,height: 40,angle: 0}).scale(0.8);this.canvas.add(oImg).renderAll();this.canvas.setActiveObject(oImg);oImg.on('mousedown', function() {self.deleteObject();});},// 回显详情信息loadDraw() {const self = this;if (self.drawinfo.id === '') return;const pointGroup = JSON.parse(self.drawinfo.pointInfo);const imgInfo = JSON.parse(self.drawinfo.imgInfo);self.bgImgSrc = self.drawinfo.img;imgInfo.src = self.drawinfo.img;// 1、加载底图fabric.util.enlivenObjects([imgInfo], objects => {objects.forEach(o => {o.selectable = false;o.hasControls = false;o.centeredScaling = false;this.canvas.add(o);});// 2、处理多边形绘制回显操作pointGroup.forEach(async (item, index) => {if (item.pointInfo !== '') {const polygon = new fabric.Polygon(item.pointInfo, {stroke: self.colorGrounp[item.alarmLevel],strokeWidth: self.drawWidth,fill: self.colorGrounpFill[item.alarmLevel],opacity: 1,selectable: false,hasBorders: false,hasControls: false,alarmLevel: item.alarmLevel});polygon.index = index;self.canvas.add(polygon);self.activeLine = null;self.activeShape = null;self.polygonMode = false;self.doDrawing = false;if (!self.readstate) {fabric.Image.fromURL(self.deleteIconURL, async img => {const _self = this;img.index = index;const oImg = await img.set({left: item.pointInfo[0].x - 20,top: item.pointInfo[0].y - 20,width: 40,height: 40,angle: 0}).scale(0.8);this.canvas.add(oImg);oImg.on('mousedown', function() {_self.deleteObject();});});}}});});self.canvas.renderAll();}}
};
</script><style lang="scss" scoped>
.el-container {flex-direction: column;
}img {display: none;
}.demo {display: flex;flex-direction: column;align-items: center;
}canvas {border: 1px dashed #2695F9;
}.draw-btn-group {width: 100%;margin-top: 10px;display: flex;align-items: center;justify-content: space-between;.el-button {color: #ffffff;}
}.tip-title {top: 40%;left: 33%;position: absolute;font-size: 16px;color: #C2C7CC;margin: 0;
}
</style>