目录
一、基于canvas画布的实用类Fabric.js的使用Part.1
Fabric.js简介
开始
方法
事件
canvas常用属性
对象属性
图层层级操作
复制和粘贴
二、基于canvas画布的实用类Fabric.js的使用Part.2
锁定
拖拽和缩放画布
分组
动画
图像滤镜
渐变
右键菜单删除
三、基于canvas画布的实用类Fabric.js的使用Part.3
自由绘画
绘制背景图片
绘制文本
绘制线和路径
自由绘制矩形
自由绘制圆形
自由绘制椭圆形
自由绘制三角形
自由绘制多边形
一、自由绘画
1、开启绘图模式

let canvas = new fabric.Canvas('canvas', {
isDrawingMode: true // 开启绘图模式
})
canvas.freeDrawingBrush.color = '#11999e' // 设置画笔颜色
canvas.freeDrawingBrush.width = 10 // 设置画笔粗细
canvas.freeDrawingBrush.shadow = new fabric.Shadow({ // 设置画笔投影
blur: 10,
offsetX: 10,
offsetY: 10,
affectStroke: true,
color: '#30e3ca'
})
2、关闭绘图模式
canvas.isDrawingMode = false
二、绘制背景图片

1、方式一:通过img元素添加
<img src="@/assets/images/logo.png" id="logo">
let img = document.getElementById('logo')
img.onload = () => {
let canvasImage = new fabric.Image(imgElement, {
left: 100, // 距离画布左侧距离
top: 100, // 距离画布顶部距离
width: 200, // 图片宽度
height: 200, // 图片高度
angle: 50, // 旋转
opacity: 1 // 透明度
})
canvas.add(canvasImage)
}
2、方式二:通过图片路径添加
let url = 'http://localhost:82/public/img/logo.png'
fabric.Image.fromURL(url, img => {
let canvasImage = img.set({
scaleX: 0.5,
scaleY: 0.5
})
canvas.add(canvasImage)
})
三、绘制文本
Fabric也提供了文本的相关功能,Fabric文本允许以面向对象的方式处理文本,原生canvas方法,只允许在非常低的级别上填充或描边文本,通过实例化fabric.Text实例,我们就可以使用文本,就像我们将使用任何其他Fabric对象:移动它,缩放它,更改其属性等, 其次它提供比canvas给我们更丰富的功能,包括:
Multiline support // 支持多行
Text alignment // 文本对齐 Left、center、right
Text background // 文本背景 背景也遵循文本对齐
Text decoration // 文字装饰 下划线Underline、上划线overline、贯穿线strike-through
Line height // 行高 使用多行文字时出错
Char spacing // 字符间距 使文本更紧凑或间距更大
Subranges // 子范围 将颜色和属性应用于文本对象的子范围
Multibyte // 多字节 支持表情符号
On canvas editing // 交互式画布编辑 可以直接在canvas上键入文本
1、基础用法

let text = new fabric.Text('Hello World!', {
left: 40,
top: 10,
fontFamily: 'Comic Sans', // 字体
fontSize: 60, // 字号
fontWeight: 600, // 字体重量(粗细),normal、bold 或 数字(100、200、400、600、800)
fontStyle: 'normal', // 字体风格 正常 normal 或 斜体 italic
charSpacing: 100, // 字距
fill: 'red', // 字体颜色
cornerColor: 'pink', // 角的颜色(被选中时)
angle: 30, // 旋转
backgroundColor: '#ffd460', // 背景色
borderColor: 'yellowGreen', // 边框颜色(被选中时)
borderScaleFactor: 4, // 边框粗细(被选中时)
borderDashArray: [10, 4, 20], // 创建边框虚线
stroke: '#3f72af', // 文字描边颜色(蓝色)
strokeWidth: 2, // 文字描边粗细
textAlign: 'left', // 对齐方式:left 左对齐; right 右对齐; center 居中
opacity: 0.8, // 不透明度
// text: '雷猴', // 文字内容,会覆盖之前设置的值
selectable: true, // 能否被选中,默认true
shadow: 'rgba(0, 0, 0, 0.5) 5px 5px 5px', // 投影
})
canvas.add(text)
2、文本修饰

// 下划线
let underlineText = new fabric.Text("I am an undrline text", {
underline: true
})
canvas.add(underlineText)
// 贯穿线
let strokeThroughText = new fabric.Text("I am a stroke-through text", {
linethrough: true,
top: 40
})
canvas.add(strokeThroughText)
// 上划线
let overlineText = new fabric.Text("I am overline text", {
overline:true,
top: 80
})
canvas.add(overlineText)
3、可编辑文本

let IText = new fabric.IText('雷猴啊,双击打几个字试下~', {
fontFamily: 'Comic Sans'
})
canvas.add(IText)
四、绘制线和路径
1、绘制直线
let line = new fabric.Line([0, 100, 100, 100], {
fill: 'green', // 填充色
stroke: 'green', // 笔触颜色
strokeWidth: 2, // 笔触宽度
});
canvas.add(line);
2、绘制虚线
在绘制直线的基础上添加属性strokeDashArray[a,b],表示每隔a个像素空b个像素。
let line = new fabric.Line([0, 100, 100, 100], {
fill: 'green', // 填充色
stroke: 'green', // 笔触颜色
strokeWidth: 2, // 笔触宽度
strokeDashArray:[3,1]
});
canvas.add(line);
3、绘制路径
Fabric.js使用 new fabric.Path 创建路径。
M:可以理解为新的起始点 x,y 坐标
L:每个折点的 x,y 坐标
z:自动闭合(自动把结束点和起始点连接起来)

let path = new fabric.Path('M 0 0 L 200 100 L 170 200 z')
path.set({
top: 120, // 距离容器顶部距离 120px
left: 120, // 距离容器左侧距离 120px
fill: 'hotpink', // 填充 亮粉色
opacity: 0.5, // 不透明度 50%
stroke: 'black', // 描边颜色 黑色
strokeWidth: 10 // 描边粗细 10px
})
上述代码第一行“M”代表“移动”命令,“M 0 0” 代表把画笔移动到(0, 0)点坐标。“L”代表“线”,“L 200 100 ”的意思是使用钢笔画一条线,从(0, 0)坐标画到(200, 100)坐标。“z” 代表让图形闭合路径。这样就画出了一个三角形。画好三角形后,我们可以用set( )方法对三角形的位置、颜色、角度、透明度等属性进行设置。
五、自由绘制矩形

<template>
<div class="canvas-box" ref="canvasBox">
<canvas id="canvas"></canvas>
<el-button @click="handleActiveRect">绘制矩形</el-button>
</div>
</template>
<script>
export default {
name: 'PointerDetail',
data () {
return {
canvas: null,
lastPoint: null, // 上次鼠标点位坐标
strokeColor: 'transparent', // 轮廓填充颜色
isActiveRect: false, // 是否激活绘制矩形
rectList: [] // 绘制的矩形列表
}
},
mounted() {
this.init()
},
methods: {
// 初始化
init() {
this.canvas = new fabric.Canvas('canvas', {
width: this.$refs.canvasBox.offsetWidth,
height: this.$refs.canvasBox.offsetHeight,
backgroundColor: '#2E3136',
selectionColor: 'transparent',
selectionBorderColor: 'transparent',
hoverCursor: 'default'
})
this.canvas.on('mouse:down', this.onMouseDown)
this.canvas.on('mouse:up', this.onMouseUp)
this.canvas.on('object:added', this.onObjectAdded)
},
// 监听鼠标按下事件
onMouseDown(opt) {
if (this.isActiveRect) {
this.lastPoint = opt.absolutePointer || null
this.strokeColor = '#00FF64'
}
},
// 监听鼠标松开事件
onMouseUp(opt) {
if (this.isActiveRect) {
this.drawRect(opt.absolutePointer)
}
},
// 绘制完成元素事件
onObjectAdded(opt) {
let target = opt.target
if (target.stroke === '#00FF64') {
this.isActiveRect && this.rectList.push(target)
}
},
// 绘制矩形
drawRect(pointer) {
if (!this.lastPoint || JSON.stringify(this.lastPoint) === JSON.stringify(pointer)) { // 点击事件,不生成矩形
return
}
let top = Math.min(this.lastPoint.y, pointer.y)
let left = Math.min(this.lastPoint.x, pointer.x)
let width = Math.abs(this.lastPoint.x - pointer.x)
let height = Math.abs(this.lastPoint.y - pointer.y)
let rect = new fabric.Rect({
top,
left,
width,
height,
fill: 'transparent',
stroke: this.strokeColor,
selectable: false
})
this.canvas.add(rect)
this.lastPoint = null
this.strokeColor = 'transparent'
},
// 激活绘制矩形
handleActiveRect() {
this.isActiveRect = !this.isActiveRect
if(this.isActiveRect) {
this.canvas.selectionBorderColor = '#00FF64'
}
}
}
}
六、自由绘制圆形

<template>
<div class="canvas-box" ref="canvasBox">
<canvas id="canvas"></canvas>
<el-button @click="handleActiveCircle">绘制圆形</el-button>
</div>
</template>
<script>
export default {
name: 'PointerDetail',
data () {
return {
canvas: null,
canvasCircle: null,
downPoint: null,
strokeColor: 'transparent', // 轮廓填充颜色
isActiveCircle: false, // 是否激活绘制圆形
circleList: [] // 绘制的圆形列表
}
},
mounted() {
this.init()
},
methods: {
// 初始化
init() {
this.canvas = new fabric.Canvas('canvas', {
width: this.$refs.canvasBox.offsetWidth,
height: this.$refs.canvasBox.offsetHeight,
backgroundColor: '#2E3136',
selectionColor: 'transparent',
selectionBorderColor: 'transparent',
hoverCursor: 'default'
})
this.canvas.on('mouse:down', this.onMouseDown)
this.canvas.on('mouse:move', this.onMouseMove)
this.canvas.on('mouse:up', this.onMouseUp)
this.canvas.on('object:added', this.onObjectAdded)
},
// 监听鼠标按下事件
onMouseDown(opt) {
if (this.isActiveCircle) {
this.downPoint = opt.absolutePointer
this.strokeColor = '#00FF64'
this.canvasCircle = new fabric.Circle({
top: this.downPoint.y,
left: this.downPoint.x,
radius: 0,
fill: 'transparent',
stroke: this.strokeColor,
strokeWidth: 2,
selectable: false,
})
this.canvas.add(this.canvasCircle)
}
},
// 监听鼠标移动事件
onMouseMove(opt) {
if (this.isActiveCircle && this.canvasCircle) {
let radius = Math.min(Math.abs(this.downPoint.x - opt.absolutePointer.x), Math.abs(this.downPoint.y - opt.absolutePointer.y)) / 2
let top = opt.absolutePointer.y > this.downPoint.y ? this.downPoint.y : this.downPoint.y - radius * 2
let left = opt.absolutePointer.x > this.downPoint.x ? this.downPoint.x : this.downPoint.x - radius * 2
this.canvasCircle.set('radius', radius)
this.canvasCircle.set('top', top)
this.canvasCircle.set('left', left)
this.canvas.requestRenderAll()
}
},
// 监听鼠标松开事件
onMouseUp(opt) {
if (this.isActiveCircle) {
if (JSON.stringify(this.downPoint) === JSON.stringify(opt.absolutePointer)) {
this.canvas.remove(this.canvasCircle)
} else {
if (this.canvasCircle){
this.canvasCircle.set('stroke', this.strokeColor)
}
}
this.canvasCircle = null
}
},
// 绘制完成元素事件
onObjectAdded(opt) {
let target = opt.target
if (target.stroke === '#00FF64') {
this.isActiveCircle && this.circleList.push(target)
}
},
// 激活绘制圆形
handleActiveCircle() {
this.isActiveCircle = !this.isActiveCircle
if(this.isActiveCircle) {
this.canvas.selectionBorderColor = '#00FF64'
}
}
}
}
七、自由绘制椭圆形

<template>
<div class="canvas-box" ref="canvasBox">
<canvas id="canvas"></canvas>
<el-button @click="handleActiveEllipse">绘制椭圆形</el-button>
</div>
</template>
<script>
export default {
name: 'PointerDetail',
data () {
return {
canvas: null,
canvasEllipse: null,
downPoint: null,
strokeColor: 'transparent', // 轮廓填充颜色
isActiveEllipse: false, // 是否激活绘制椭圆形
ellipseList: [] // 绘制的椭圆形列表
}
},
mounted() {
this.init()
},
methods: {
// 初始化
init() {
this.canvas = new fabric.Canvas('canvas', {
width: this.$refs.canvasBox.offsetWidth,
height: this.$refs.canvasBox.offsetHeight,
backgroundColor: '#2E3136',
selectionColor: 'transparent',
selectionBorderColor: 'transparent',
hoverCursor: 'default'
})
this.canvas.on('mouse:down', this.onMouseDown)
this.canvas.on('mouse:move', this.onMouseMove)
this.canvas.on('mouse:up', this.onMouseUp)
this.canvas.on('object:added', this.onObjectAdded)
},
// 监听鼠标按下事件
onMouseDown(opt) {
if (this.isActiveEllipse) {
this.downPoint = opt.absolutePointer
this.strokeColor = '#00FF64'
this.canvasEllipse = new fabric.Ellipse({
top: this.downPoint.y,
left: this.downPoint.x,
rx: 0,
ry: 0,
fill: 'transparent',
stroke: this.strokeColor,
strokeWidth: 2,
selectable: false,
})
this.canvas.add(this.canvasEllipse)
}
},
// 监听鼠标移动事件
onMouseMove(opt) {
if (this.isActiveEllipse && this.canvasEllipse) {
let rx = Math.abs(this.downPoint.x - opt.absolutePointer.x) / 2
let ry = Math.abs(this.downPoint.y - opt.absolutePointer.y) / 2
let top = opt.absolutePointer.y > this.downPoint.y ? this.downPoint.y : this.downPoint.y - ry * 2
let left = opt.absolutePointer.x > this.downPoint.x ? this.downPoint.x : this.downPoint.x - rx * 2
this.canvasEllipse.set('rx', rx)
this.canvasEllipse.set('ry', ry)
this.canvasEllipse.set('top', top)
this.canvasEllipse.set('left', left)
this.canvas.requestRenderAll()
}
},
// 监听鼠标松开事件
onMouseUp(opt) {
if (this.isActiveEllipse) {
if (JSON.stringify(this.downPoint) === JSON.stringify(opt.absolutePointer)) {
this.canvas.remove(this.canvasEllipse)
} else {
if (this.canvasEllipse){
this.canvasEllipse.set('stroke', this.strokeColor)
}
}
this.canvasEllipse = null
}
},
// 绘制完成元素事件
onObjectAdded(opt) {
let target = opt.target
if (target.stroke === '#00FF64') {
this.isActiveEllipse && this.ellipseList.push(target)
}
},
// 激活绘制椭圆形
handleActiveEllipse() {
this.isActiveEllipse = !this.isActiveEllipse
if(this.isActiveEllipse) {
this.canvas.selectionBorderColor = '#00FF64'
}
}
}
}
八、自由绘制三角形

<template>
<div class="canvas-box" ref="canvasBox">
<canvas id="canvas"></canvas>
<el-button @click="handleActiveTriangle">绘制三角形</el-button>
</div>
</template>
<script>
export default {
name: 'PointerDetail',
data () {
return {
canvas: null,
canvasTriangle: null,
downPoint: null,
strokeColor: 'transparent', // 轮廓填充颜色
isActiveTriangle: false, // 是否激活绘制三角形
triangleList: [] // 绘制的三角形列表
}
},
mounted() {
this.init()
},
methods: {
// 初始化
init() {
this.canvas = new fabric.Canvas('canvas', {
width: this.$refs.canvasBox.offsetWidth,
height: this.$refs.canvasBox.offsetHeight,
backgroundColor: '#2E3136',
selectionColor: 'transparent',
selectionBorderColor: 'transparent',
hoverCursor: 'default'
})
this.canvas.on('mouse:down', this.onMouseDown)
this.canvas.on('mouse:move', this.onMouseMove)
this.canvas.on('mouse:up', this.onMouseUp)
this.canvas.on('object:added', this.onObjectAdded)
},
// 监听鼠标按下事件
onMouseDown(opt) {
if (this.isActiveTriangle) {
this.downPoint = opt.absolutePointer
this.strokeColor = '#00FF64'
this.canvasTriangle = new fabric.Triangle({
top: this.downPoint.y,
left: this.downPoint.x,
width: 0,
height: 0,
fill: 'transparent',
stroke: this.strokeColor,
strokeWidth: 2,
selectable: false,
})
this.canvas.add(this.canvasTriangle)
}
},
// 监听鼠标移动事件
onMouseMove(opt) {
if (this.isActiveTriangle && this.canvasTriangle) {
let width = Math.abs(this.downPoint.x - opt.absolutePointer.x)
let height = Math.abs(this.downPoint.y - opt.absolutePointer.y)
let top = opt.absolutePointer.y > this.downPoint.y ? this.downPoint.y : opt.absolutePointer.y
let left = opt.absolutePointer.x > this.downPoint.x ? this.downPoint.x : opt.absolutePointer.x
this.canvasTriangle.set('width', width)
this.canvasTriangle.set('height', height)
this.canvasTriangle.set('top', top)
this.canvasTriangle.set('left', left)
this.canvas.requestRenderAll()
}
},
// 监听鼠标松开事件
onMouseUp(opt) {
if (this.isActiveTriangle) {
if (JSON.stringify(this.downPoint) === JSON.stringify(opt.absolutePointer)) {
this.canvas.remove(this.canvasTriangle)
} else {
if (this.canvasTriangle){
this.canvasTriangle.set('stroke', this.strokeColor)
}
}
this.canvasTriangle = null
}
},
// 绘制完成元素事件
onObjectAdded(opt) {
let target = opt.target
if (target.stroke === '#00FF64') {
this.isActiveTriangle && this.triangleList.push(target)
}
},
// 激活绘制矩形
handleActiveTriangle() {
this.isActiveTriangle = !this.isActiveTriangle
if(this.isActiveTriangle) {
this.canvas.selectionBorderColor = '#00FF64'
}
}
}
}
九、自由绘制多边形

<template>
<div class="canvas-box" ref="canvasBox">
<canvas id="canvas"></canvas>
<el-button @click="handleActivePolygon">绘制多边形</el-button>
</div>
</template>
<script>
export default {
name: 'PointerDetail',
data () {
return {
canvas: null,
canvasPolygon: null,
strokeColor: 'transparent', // 轮廓填充颜色
isActivePolygon: false, // 是否激活绘制多边形
polygonList: [] // 绘制的多边形列表
}
},
mounted() {
this.init()
},
methods: {
// 初始化
init() {
this.canvas = new fabric.Canvas('canvas', {
width: this.$refs.canvasBox.offsetWidth,
height: this.$refs.canvasBox.offsetHeight,
backgroundColor: '#2E3136',
selectionColor: 'transparent',
selectionBorderColor: 'transparent',
hoverCursor: 'default'
})
this.canvas.on('mouse:down', this.onMouseDown)
this.canvas.on('mouse:move', this.onMouseMove)
this.canvas.on('mouse:dblclick', this.onDblclick)
this.canvas.on('object:added', this.onObjectAdded)
},
// 监听鼠标按下事件
onMouseDown(opt) {
if (this.isActivePolygon) {
this.strokeColor = '#00FF64'
if (this.canvasPolygon === null) {
this.createPolygon(opt)
} else {
this.changeCurrentPolygon(opt)
}
}
},
// 监听鼠标移动事件
onMouseMove(opt) {
if (this.isActivePolygon && this.canvasPolygon) {
this.changePolygonBelt(opt)
}
},
// 鼠标双击事件
onDblclick(opt) {
this.finishPolygon(opt)
},
// 绘制完成元素事件
onObjectAdded(opt) {
let target = opt.target
if (target.stroke === '#00FF64') {
this.isActivePolygon && this.polygonList.push(target)
}
},
// 创建多边形
createPolygon(opt) {
this.canvasPolygon = new fabric.Polygon([
{ x: opt.absolutePointer.x, y: opt.absolutePointer.y },
{ x: opt.absolutePointer.x, y: opt.absolutePointer.y }
], {
fill: 'transparent',
stroke: this.strokeColor,
objectCaching: false
})
this.canvas.add(this.canvasPolygon)
},
// 修改当前正在创建的多边形
changeCurrentPolygon(opt) {
let points = this.canvasPolygon.points
points.push({
x: opt.absolutePointer.x,
y: opt.absolutePointer.y
})
this.canvas.requestRenderAll()
},
// 多边形橡皮带
changePolygonBelt(opt) {
let points = this.canvasPolygon.points
points[points.length - 1].x = opt.absolutePointer.x
points[points.length - 1].y = opt.absolutePointer.y
this.canvas.requestRenderAll()
},
// 完成多边形绘制
finishPolygon(opt) {
let points = this.canvasPolygon.points
points[points.length - 1].x = opt.absolutePointer.x
points[points.length - 1].y = opt.absolutePointer.y
points.pop()
points.pop()
this.canvas.remove(this.canvasPolygon)
if (points.length > 2) {
let polygon = new fabric.Polygon(points, {
stroke: this.strokeColor,
fill: 'transparent',
selectable: false
})
this.canvas.add(polygon)
} else {
this.$message.warning('标记框小于最小标定像素!')
}
this.canvasPolygon = null
this.canvas.requestRenderAll()
this.strokeColor = 'transparent'
},
// 激活绘制多边形
handleActivePolygon() {
this.isActivePolygon = !this.isActivePolygon
if(this.isActivePolygon) {
this.canvas.selectionBorderColor = '#00FF64'
}
}
}
}