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的语法分析器. 你可以轻松的使用 ...
随机推荐
- memcache、mongodb、redis的对比区别
>>Memcached Memcached的优点:Memcached可以利用多核优势,单实例吞吐量极高,可以达到几十万QPS(取决于key.value的字节大小以及服务器硬件性能,日常环境 ...
- windows下基于(QPC)实现的微秒级延时
1.为什么会写windows下微秒级延时 在上一篇 实现memcpy()函数及过程总结 中测试memcpy的效率中,测试时间的拷贝效率在微秒级别,需要使用微秒级时间间隔计数. windows下提供Qu ...
- 小白jquery横向菜单弹出菜单制作
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- JavaSE---Runtime类
1.概述 1.1 Runtime类 代表 java程序运行时环境: 1.2 Runtime类 提供的类方法: getRuntime():获取Runtime实例: gc():通知垃圾回收器回收资源: ...
- JavaSE---环境配置
1.概述 1.1 PATH环境变量 a,Java程序 编译.运行时 需要用到java.javac命令,虽然计算机中已经安装了JDK,但是计算机不知道去哪里找这个命令: b,计算机如何查找命令呢 ...
- API登录验证
客户端 客户端token加在header头中,通过request发送给服务端 服务端 服务端 通过request.META.get(HTTP_TOKEN)拿到客户端传来的token 然后与服务器事先存 ...
- 【Dart学习】--Dart之正则表达式相关方法总结
一,部分属性 RegExp exp = new RegExp(r"(\w+)"); 返回正则表达式的哈希码 print(exp.hashCode); 正则表达式是否区分大小写 pr ...
- haproxy笔记
haproxy安装.启动.日志配置 方法1:#安装 yum install haproxy -y #日志配置 sed -i 's/^#$ModLoad imudp/$ModLoad imudp/g' ...
- bind-dns服务器搭建
环境:主服务器上IP为192.168.159.30 安装相关包bind dns服务器 bind-utils提供nslookup dig等命令 yum -y install bind bind-uti ...
- iOS 获取self类型
类型转换快速写法 typeof(self) bself = self; 版权声明:本文为博主原创文章,未经博主允许不得转载.