Fabric.js的使用
最近项目有一个绘制的功能,搜了一圈发现fabric.js口碑不错,但是文档稀缺,于是东看看西搜搜的把项目的需求都给实现了,想分享一下。
篇幅有点长,但看完后可以轻松驾驭fabric。我的项目是基于VUE+webpack的。
先来看一下整体效果
1.安装fabric
在node环境下安装fabric.js需要先安装 jsdom 和canvas
①安装jsdom依赖
npm install jsdom --save-dev
②安装canvas依赖
npm install canvas --save-dev
③安装fabric.js
npm install fabricjs --save-dev
安装完成后 npm run dev启动你的项目就可以,无需更改其他配置
2.使用fabric
fabric.js是基于canvas的一款强大的绘制插件,我的项目里主要包括功能如下
`铅笔 箭头 直线 虚线 圆 椭圆 矩形 三角形 输入文字 移动 清空 撤回 前进 绘制图片 上传背景图`
使用之前你需要在你使用的vue页面导入fabric
import { fabric } from 'fabric'
①初始化
你的html需要有一个canvas标签: <canvas id="canvas"></canvas>
初始化:
let _this = this //下面得用this.canvasObj = new fabric.Canvas('canvas', { isDrawingMode: true, //设置是否可以绘制 selectable: false, //设置是否可以选中拖动 fabric提供的 selection: false })
this.canvasObj.setWidth(this.canvasWidth) //设置画布的宽度this.canvasObj.setHeight(this.canvasHeight) //设置画布的高度 /* this.canvasWidth 和 this.canvasHeight 是我在 computed 里定义的 */ //绑定画板时间 fabric为我们提供了一些事件this.canvasObj.on({ 'mouse:down': (o) => { //鼠标在画布上按下事件(起点) //mouseFrom.x 和 mouseFrom.y 是在data中定义的数据 可以打印这个o看看 this.mouseFrom.x = o.pointer.x //鼠标按下的X的起点 this.mouseFrom.y = o.pointer.y //鼠标按下的y的起点 this.doDrawing = true //绘制设为true }, 'mouse:up': (o) => { //鼠标抬起的事件(终点) //mouseTo.x 和 mouseTo.y 也是在data中定义的数据 this.mouseTo.x = o.pointer.x this.mouseTo.y = o.pointer.y
this.drawingObject = null this.doDrawing = false //停止绘制
}, 'mouse:move': (o) => { //鼠标在移动中的事件 this.offsetX = o.pointer.x.toFixed(0) //因为是小数,所以我给取整 this.offsetY = o.pointer.y.toFixed(0) if(!_this.doDrawing){ return } this.mouseTo.x = o.pointer.x this.mouseTo.y = o.pointer.y if(this.sineNum === 1){ //这个if是我的项目里有自定义图片的功能 this.drawing() }else if(this.sineNum === 2){ this.diy() } }, 'object:move': (e) => { e.target.opacity = 0.5 //你绘画在画布上对象,移动它们的时候,让它们的透明度变成0.5 }, 'object:added': (e) => { if(!this.controlFlag){ this.redo = [] //撤回用的 } this.controlFlag = false }, 'object:modified': (e) => { e.target.opacity = 1 }})
初始化就这样完成了!
②点击不同形状的icon绘制不同的图形(左边那一列是写在data里的数据,然后通过v-for加载出来的)
toolsArr: [ { name: 'pencil', icon: 'iconpen', label: '铅笔' },]格式就是这样的。然后我们给每个li添加一个名叫 handleTools的事件
handleTools (tools, idx) { //tools是item,idx是index this.sineNum = 1 //把sineNum设置为1 就会去加载drawing方法 console.log(tools) this.initIdx = idx //这是给li绑定的高亮的样式 this.$store.commit('TOOGLE_TOOLS', tools.name) //把我们点击的图形保存到vuex里 if (tools.name === 'delete') { //清空单独处理 this.resetObj() //重置的方法 this.canvasObj.clear() //清空画布 this.canvasObj.renderAll() //重新渲染 } else if (tools.name === 'text') { //文字也单独处理 因为在选择到文字的时候 有一个改变文字大小的range this.canvasObj.isDrawingMode = true this.drawing() this.choseItem = true //文字大小range是否显示 是 } else { this.drawing() //调用drawing方法 this.choseItem = false //否 } }
之前存到vuex里的数据,现在我们要拿出来:
watch: { '$store.state.drawType': function () { this.currentTool = this.$store.state.drawType } }
接下来先看看resetObj方法:
resetObj () { this.canvasObj.isDrawingMode = false this.canvasObj.selectable = false this.canvasObj.selection = false this.canvasObj.skipTargetFind = true }
然后是drawing方法:(重点)------用到一个switch case
drawing () { if (this.drawingObject) { this.canvasObj.remove(this.drawingObject) } let canvasObject = null switch (this.currentTool) { case 'pencil': //name为铅笔时 this.resetObj() this.canvasObj.isDrawingMode = true this.canvasObj.freeDrawingBrush.color = this.strokeColor //画笔颜色 this.canvasObj.freeDrawingBrush.width = this.strokeWidths //画笔宽度 break case 'line': //name为直线 this.resetObj() canvasObject = new fabric.Line([this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y], { //fabric.Line是fabric封装的方法 直接用就好了 stroke: this.strokeColor, //画笔颜色 strokeWidth: this.strokeWidths //画笔宽度 }) console.log(canvasObject) break case 'arrow': this.resetObj() //isFill 是用来判断是否要填充颜色 if (this.isFill === false) { this.fillColor = '' } else { this.fillColor = this.strokeInnerColor } canvasObject = new fabric.Path(this.drawArrow(this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y, 17.5, 17.5), { stroke: this.strokeColor, fill: this.fillColor, strokeWidth: this.strokeWidths }) break case 'xuxian': this.resetObj() canvasObject = new fabric.Line([this.mouseFrom.x, this.mouseFrom.y, this.mouseTo.x, this.mouseTo.y], { strokeDashArray: [3, 3], //[3,3]是每个3个像素,间隔3个像素 后面的参数是间隔数 stroke: this.strokeColor, strokeWidth: this.strokeWidths }) break case 'juxing': this.resetObj() if (this.isFill === false) { this.fillColor = '' } else { this.fillColor = this.strokeInnerColor } canvasObject = new fabric.Rect({ left: this.mouseFrom.x, top: this.mouseFrom.y, width: this.mouseTo.x - this.mouseFrom.x, height: this.mouseTo.y - this.mouseFrom.y, stroke: this.strokeColor, fill: this.fillColor }) console.log(canvasObject) break case 'circle': this.resetObj() if (this.isFill === false) { this.fillColor = '' } else { this.fillColor = this.strokeInnerColor } 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; //Math.sqrt 这个方法是返回平方根 计算圆的半径时用的是勾股定理 canvasObject = new fabric.Circle({ left: this.mouseFrom.x, top: this.mouseFrom.y, radius: radius, //圆的半径 stroke: this.strokeColor, strokeWidth: this.strokeWidths, fill: this.fillColor }) console.log(canvasObject) break case 'ellipse': //椭圆 this.resetObj() let left = this.mouseFrom.x let top = this.mouseFrom.y if (this.isFill === false) { this.fillColor = '' } else { this.fillColor = this.strokeInnerColor } let ellipse = Math.sqrt((this.mouseTo.x - left) * (this.mouseTo.x - left) + (this.mouseTo.y - top) * (this.mouseTo.y - top)) / 2 canvasObject = new fabric.Ellipse({ left: left, top: top, fill: this.fillColor, originX: 'center', //从X轴中心点绘制 originY: 'center', //从Y轴中心点绘制 rx: Math.abs(left - this.mouseTo.x), //x轴半径 ry: Math.abs(top - this.mouseTo.y), //y轴半径 math.abs返回绝对值 stroke: this.strokeColor, strokeWidth: this.strokeWidths }) break case 'equilateral': this.resetObj() if (this.isFill === false) { this.fillColor = '' } else { this.fillColor = this.strokeInnerColor } let height = this.mouseTo.y - this.mouseFrom.y canvasObject = 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.strokeColor, strokeWidth: this.strokeWidths, fill: this.fillColor }) break case 'text': this.resetObj() let textbox = new fabric.Textbox('', { left: this.mouseFrom.x, top: this.mouseFrom.y, width: 150, fontSize: this.fontSizes, fill: this.strokeColor, hasControls: false }) this.canvasObj.add(textbox) textbox.enterEditing() console.log(textbox) console.log(this.canvasObj) break case 'draggle': //移动 this.canvasObj.isDrawingMode = false this.canvasObj.skipTargetFind = false this.canvasObj.selectable = true this.canvasObj.selection = true break case 'undo': //撤回 this.resetObj() if (this.canvasObj._objects.length > 0) { this.redo.push(this.canvasObj._objects.pop()) this.canvasObj.renderAll() } break case 'redo': //前进 this.resetObj() if (this.redo.length > 0) { this.controlFlag = true this.canvasObj.add(this.redo.pop()) this.canvasObj.renderAll() } break case 'eraser': //橡皮擦功能还在研究中心0.0 console.log('擦掉') this.resetObj() //this.canvasObj.clearRect(12, 12, 20, 20) //canvasObject = new fabric.clear() break default: break } if (canvasObject) { this.canvasObj.add(canvasObject) //把要绘制的内容添加到画布中 this.canvasObj.renderAll() this.drawingObject = canvasObject } },
这样你就可以在页面上绘制大多数图形了 其中有个橡皮擦功能还在研究中。。。
③设置背景图片:
正上方有个点击上传 用el-upload做的
fabric.Image.fromURL(imgUrl, (img) => { //imgUrl接收路径和base64 这里你上传的照片 肯定是用base64 img是固定写法 console.log(img) this.bgcW = img.width this.bgcH = img.height img.set({ width: img.width, height: img.height }) this.canvasObj.setBackgroundImage(img, this.canvasObj.renderAll.bind(this.canvasObj)) this.canvasObj.renderAll() })
④至于在桌面上绘制图片,有的需求里没有 但我这里有 前面我们设置了sineNum=1 加载drawing这个方法 当sineName=2的时候 我们加载diy() 这个方法
点击这个图标的时候,弹出popover 这里面的图片是通过接口加载出来的 当点击里面的图片的时候 在点击画布 画布上就会加载刚刚我点击的图片
这个地方的实现跟设置背景图片差不多,代码如下:
diy () { if (this.drawingObject) { this.canvasObj.remove(this.drawingObject) } let canvasObject = null console.log(this.diyImage) this.resetObj() canvasObject = fabric.Image.fromURL(this.diyImage, (img) => { console.log(img) img.set({ left: this.mouseFrom.x, top: this.mouseFrom.y, fill: '' }) this.canvasObj.add(img) }) if (canvasObject) { this.canvasObj.add(canvasObject) this.drawingObject = canvasObject } },
然后可以把当前画好的访问后台接口保存起来。因为我的项目里有一些其他功能,这里就不把全部代码贴出来了。
fabric一些常用的方法都在这儿了,如果有什么错误,还望指教,互相探讨。
================================分割线 2019/12/20======================================== 箭头的实现方法:
/*箭头的方法*/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}
Fabric.js的使用的更多相关文章
- HTML5 Canvas JavaScript库 Fabric.js 使用经验
首先,表明我的态度:采用 Flash 才是最优方案,不建议使用 HTML 5 的 Canvas 做一些生产/工业级的网页应用. Flash的优势一是浏览器支持好,二是代码成熟稳定.而HTML5 的 C ...
- fabric.js和高级画板
本文介绍fabric.js框架使用,以及使用fabricjs打造一个高级画板程序. 高级画板功能介绍 全局绘制颜色选择 护眼模式.网格模式切换 自由绘制 画箭头 画直线 画虚线 画圆/椭圆/矩形/直角 ...
- fabric.js 学习
官网地址:http://fabricjs.com/ git https://github.com/kangax/fabric.js/ <!DOCTYPE html> < ...
- Fabric.js canvas 图形库
1.github地址: https://github.com/fabricjs/fabric.js 2.简述 Fabric.js将canvas的编程变得简单.同时在canvas上添加了交互.交互包括: ...
- fabric.js 知识点整理
fabric.js是一个很好用的 canvas 操作插件,下面整理了一些平时项目中用到的知识点: //1: 获得画布上的所有对象: var items = canvas.getObjects(); / ...
- Canvas实用库Fabric.js使用手册
简介什么是Fabric.js? Fabric.js是一个可以简化Canvas程序编写的库. Fabric.js为Canvas提供所缺少的对象模型, svg parser, 交互和一整套其他不可或缺的工 ...
- (转)第05节:Fabric.js的动画设置
凡是出色的Canvas库都少不了制作动画的方法,Fabric.js也不例外,它有着编写简单且功能强大的动画助手,这就是animate( )方法. animate主要使用代码如下: rect.anima ...
- (转)第04节:Fabric.js用路径画不规则图形
在Canvas上画方形.圆形.三角形都是很容易的,只要调用fabric对应的方法就可以了,但这些都是规则的图形,如果你想画一个不规则的图形,这时候你可以用fabric.js提供的路径绘图方法.所谓路径 ...
- (转)第01节:初识简单而且强大的Fabric.js库
Fabric.js是一个功能强大和简单Javascript HTML5的canvas库.Fabric提供了很多可以互动的Canvas元素,还在canvas上提供了SVG的语法分析器. 你可以轻松的使用 ...
随机推荐
- Python中yaml和json文件的读取和应用
Python对yaml和json文件的读取: yaml文件读取: 首先创建一个yaml文件test.yaml import yaml #引入包 f=open(path) #建立Python的文件 ...
- 集成swagger
1.看官方文档 https://docs.microsoft.com/zh-cn/aspnet/core/tutorials/getting-started-with-swashbuckle?view ...
- 【leetcode】934. Shortest Bridge
题目如下: In a given 2D binary array A, there are two islands. (An island is a 4-directionally connecte ...
- 【leetcode】926.Flip String to Monotone Increasing
题目如下: A string of '0's and '1's is monotone increasing if it consists of some number of '0's (possib ...
- 基于CentOS 7.3 安装Ceph Jewel 10.2.9
https://www.lijiawang.org/posts/intsall-ceph.html 配置说明: 采用了4台centos7.3系统的虚拟机,1台Ceph-Master作为安装节点,NTP ...
- 「NOI2017」游戏 解题报告
「NOI2017」游戏 \(d\)这么小,你考虑直接对\(d\)个东西暴力 枚举\(x\)为\(a\)或\(b\)(\(c\)就不用了,因为\(a,b\)已经包含\(c\))了,剩下的就是个\(2-s ...
- paper 144:人生苦短,快用Python
1.Python 语言特点 Python是一种面向对象.直译式计算机程序设计语言,这种语言的语法简捷而清晰,具有丰富和强大的类库,基本上能胜任你平时需要的编程工作. Python的优点: (1)编写的 ...
- ibatis 中的 $和#的区别
在sql配置中比如in(#rewr#) 与in ($rewr$) 在Ibatis中我们使用SqlMap进行Sql查询时需要引用参数,在参数引用中遇到的符号#和$之间的区分为,#可以进行与编译,进行类型 ...
- Mamen所需要的jar包怎么生成
Mamen所需要的jar包怎么生成 使用 mamen 难免碰到,不知道的 jar 包,不知道怎么在 pom 文件中写,分享一个网址,可以把你想要的 jar 包生成 pom 配置文件,个人感觉非常好用. ...
- 【lua学习笔记】--- 数据类型
print("hello world!") --[注释方法]-- 单行注释 对应C# //--[[ 多行注释 /* 对应C# */]]-- -- [数据类型]--1 nil 空值 ...