Fabric.js简易小画家实作
2018-11-27 23:33:56
1535次阅读
0个评论
今天就来复习昨天我们学到的 Fabricjs 绘画功能来做一个简易的小画家吧。
透过 Fabricjs 我们可以相当快速又简单的做出一个类似画板的功能,让使用者能够随意的切换画笔顏色、粗细、阴影等样式。
最后会在特别介绍 Fabricjs 将 canvas 转换成图片的功能。
先来看看做出来的结果
製作过程
将 HTML 按钮和控制项產生出来,帮每个按钮设定 id 让我们之后可以控制,并且存取他们。
写出控制 canvas 事件要执行的 function,透过控制我们所建立的 canvas 实例来操控笔刷样式和切换模式,透过昨天我们所练习的操作画笔样式的操作。
绑定按钮、input 控制项事件,和我们写好的 function 结合,做出对应的动作
匯出功能
今天有做了一个之前没有介绍到的新功能,也就是使用者绘製完后,最后能够直接的匯出成图档的功能。
Fabricjs 主要能将 canvas 匯出成 jpeg 和 png 格式。
若使用 jpeg 格式能够调整整体输出的画质。
canvas.toDataURL
透过 canvas.toDataURL 能够轻鬆地将 canvas 转成 Base64 的编码,再透过瀏览器下载到本机,且可传入一些基本设定值。
options
format : 'image/png' | 'image/jpeg'
选择要输出成 png or jpeg 档,这边须注意到我自己在做的时候,原本只使用 'png' 和 'jpeg'作為参数,但是这样输出 jpeg 的 Base64 编码会有点问题,需要在前面加上 'image/' 当作前坠,也就是 'image/png' | 'image/jpeg' 这样输出就没有问题了。
top、left、width、height 这几个参数用来设定你要输出画布的大小
multiplier 这个参数可以缩放你所输出的 canvas ,参数為缩放倍率 ex: 0.5 输出大小為原本一半
quality 可以调整输出图片的质量,范围為 0..~1
完整程式
HTML
css
javascript
透过 Fabricjs 我们可以相当快速又简单的做出一个类似画板的功能,让使用者能够随意的切换画笔顏色、粗细、阴影等样式。
最后会在特别介绍 Fabricjs 将 canvas 转换成图片的功能。
先来看看做出来的结果
製作过程
将 HTML 按钮和控制项產生出来,帮每个按钮设定 id 让我们之后可以控制,并且存取他们。
const $ = (id) => document.getElementById(id)
const drawingOptionArea = $('drawingOptionArea')
const clearBtn = $('clear')
const modeBtn = $('mode')
const lineWidthInput = $('lineWidthInput')
const lineWidthValue = $('lineWidthValue')
const lineColorInput = $('lineColorInput')
...略
写出控制 canvas 事件要执行的 function,透过控制我们所建立的 canvas 实例来操控笔刷样式和切换模式,透过昨天我们所练习的操作画笔样式的操作。
function clearCanvas () {
canvas.clear()
}
function toggleMode () {
canvas.isDrawingMode = !canvas.isDrawingMode
if (!canvas.isDrawingMode) {
modeBtn.innerHTML = '切换成画笔模式'
drawingOptionArea.style.display = 'none'
} else {
modeBtn.innerHTML = '切换成物件模式'
drawingOptionArea.style.display = ''
}
}
function changeLineColor () {
canvas.freeDrawingBrush.color = this.value
}
function changeShadowBlur () {
myShadow.blur = this.value
canvas.freeDrawingBrush.setShadow(myShadow)
shadowBlurValue.innerHTML = this.value
}
...略
绑定按钮、input 控制项事件,和我们写好的 function 结合,做出对应的动作
mode.addEventListener('click', toggleMode)
lineWidthInput.addEventListener('change', changeLineWidth)
lineColorInput.addEventListener('change', changeLineColor)
shadowColorInput.addEventListener('change', changeShadowColor)
shadowBlurInput.addEventListener('change', changeShadowBlur)
...略
匯出功能
今天有做了一个之前没有介绍到的新功能,也就是使用者绘製完后,最后能够直接的匯出成图档的功能。
Fabricjs 主要能将 canvas 匯出成 jpeg 和 png 格式。
若使用 jpeg 格式能够调整整体输出的画质。
canvas.toDataURL
透过 canvas.toDataURL 能够轻鬆地将 canvas 转成 Base64 的编码,再透过瀏览器下载到本机,且可传入一些基本设定值。
options
format : 'image/png' | 'image/jpeg'
选择要输出成 png or jpeg 档,这边须注意到我自己在做的时候,原本只使用 'png' 和 'jpeg'作為参数,但是这样输出 jpeg 的 Base64 编码会有点问题,需要在前面加上 'image/' 当作前坠,也就是 'image/png' | 'image/jpeg' 这样输出就没有问题了。
top、left、width、height 这几个参数用来设定你要输出画布的大小
multiplier 这个参数可以缩放你所输出的 canvas ,参数為缩放倍率 ex: 0.5 输出大小為原本一半
quality 可以调整输出图片的质量,范围為 0..~1
function output (formatType) {
const dataURL = canvas.toDataURL({
format: `image/${formatType}`,
top: 0,
left: 0,
width: window.innerWidth,
height: window.innerHeight,
multiplier: 0.5,
quality: 0.1
})
const a = document.createElement('a')
a.href = dataURL
a.download = `output.${formatType}`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
完整程式
HTML
<canvas id="canvas"></canvas>
<div class="options">
<div>
<button id="mode" >切换成物件模式</button>
<button id="clear">清除</button>
<button id="outputJpgBtn">匯出成 jpeg</button>
<button id="outputPngBtn">匯出成 png</button>
</div>
<div id="drawingOptionArea">
<div>
<label>粗度:</label>
<input type="range" min="0" max="150" id="lineWidthInput" value="1">
<span id="lineWidthValue">1</span>
</div>
<div>
<label>顏色:</label>
<input type="color" min="0" max="150" id="lineColorInput">
</div>
<div>
<label>阴影顏色:</label>
<input type="color" min="0" max="150" id="shadowColorInput">
</div>
<div>
<label>阴影模糊:</label>
<input type="range" min="0" max="30" id="shadowBlurInput" value="1">
<span id="shadowBlurValue">1</span>
</div>
<div>
<label>阴影 X 轴 偏移:</label>
<input type="range" min="0" max="50" id="shadowOffsetXInput" value="1">
<span id="shadowOffsetXValue">1</span>
</div>
<div>
<label>阴影 Y 轴 偏移:</label>
<input type="range" min="0" max="50" id="shadowOffsetYInput" value="1">
<span id="shadowOffsetYValue">1</span>
</div>
</div>
</div>
css
canvas {
border: 1px solid #000;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
label {
display: inline-block;
width: 200px;
color: white;
}
#drawingOptionArea {
width: 380px;
}
#drawingOptionArea > div {
background-color: rgba(0,0,0,0.5);
border-bottom: 1px solid rgba(255,255,255,0.1)
}
.options {
position: absolute;
top: 0;
left: 0;
background-color: #878787;
}
span {
color: #fff
}
javascript
const canvas = new fabric.Canvas('canvas', {
width: window.innerWidth,
height: window.innerHeight
})
const myShadow = {
color: 'black',
blur: 1,
offsetX: 1,
offsetY: 1
}
const $ = (id) => document.getElementById(id)
const drawingOptionArea = $('drawingOptionArea')
const clearBtn = $('clear')
const modeBtn = $('mode')
const lineWidthInput = $('lineWidthInput')
const lineWidthValue = $('lineWidthValue')
const lineColorInput = $('lineColorInput')
const shadowColorInput = $('shadowColorInput')
const shadowBlurInput = $('shadowBlurInput')
const shadowBlurValue = $('shadowBlurValue')
const shadowOffsetXInput = $('shadowOffsetXInput')
const shadowOffsetXValue = $('shadowOffsetXValue')
const shadowOffsetYInput = $('shadowOffsetYInput')
const shadowOffsetYValue = $('shadowOffsetYValue')
const outputJpegBtn = $('outputJpgBtn')
const outputPngBtn = $('outputPngBtn')
const brushSelector = $('brushSelect')
function toggleMode () {
canvas.isDrawingMode = !canvas.isDrawingMode
if (!canvas.isDrawingMode) {
modeBtn.innerHTML = '切换成画笔模式'
drawingOptionArea.style.display = 'none'
} else {
modeBtn.innerHTML = '切换成物件模式'
drawingOptionArea.style.display = ''
}
}
function changeLineWidth () {
const newWidth = parseInt(this.value, 10) || 1
canvas.freeDrawingBrush.width = newWidth
lineWidthValue.innerHTML = newWidth
}
function changeLineColor () {
canvas.freeDrawingBrush.color = this.value
}
function changeShadowBlur () {
myShadow.blur = this.value
canvas.freeDrawingBrush.setShadow(myShadow)
shadowBlurValue.innerHTML = this.value
}
function changeShadowColor () {
myShadow.color = this.value
canvas.freeDrawingBrush.setShadow(myShadow)
}
function changeShadowOffsetX () {
myShadow.offsetX = this.value
canvas.freeDrawingBrush.setShadow(myShadow)
shadowOffsetXValue.innerHTML = this.value
}
function changeShadowOffsetY () {
myShadow.offsetY = this.value
canvas.freeDrawingBrush.setShadow(myShadow)
shadowOffsetYValue.innerHTML = this.value
}
function changeShadowColor () {
myShadow.color = this.value
canvas.freeDrawingBrush.setShadow(myShadow)
canvas.freeDrawingBrush.shadow.color = this.value
}
function clearCanvas () {
canvas.clear()
}
function output (formatType) {
const dataURL = canvas.toDataURL({
format: `image/${formatType}`,
top: 0,
left: 0,
width: window.innerWidth,
height: window.innerHeight,
multiplier: 1,
quality: 0.1
})
const a = document.createElement('a')
a.href = dataURL
a.download = `output.${formatType}`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
}
function selectBrush () {
if (this.value === 'Square') {
const squareBrush = new fabric.PatternBrush(canvas)
// getPatternSrc 取得要重复绘製的图形 Canvas
squareBrush.getPatternSrc = function() {
const squareWidth = 30
const squareDistance = 2
// 创立一个暂存 canvas 来绘製要画的图案
const patternCanvas = fabric.document.createElement('canvas')
// canvas 总大小為每一格画笔的大小
patternCanvas.width = patternCanvas.height = squareWidth + squareDistance
const ctx = patternCanvas.getContext('2d')
ctx.fillStyle = this.color
ctx.fillRect(0, 0, squareWidth, squareWidth)
// 回传绘製完毕的 canvas
return patternCanvas
}
canvas.freeDrawingBrush = squareBrush
} else {
canvas.freeDrawingBrush = new fabric[this.value + 'Brush'](canvas)
}
canvas.freeDrawingBrush.color = lineColorInput.value
canvas.freeDrawingBrush.width = parseInt(lineWidthInput.value, 10) || 1
canvas.freeDrawingBrush.setShadow(myShadow)
}
mode.addEventListener('click', toggleMode)
lineWidthInput.addEventListener('change', changeLineWidth)
lineColorInput.addEventListener('change', changeLineColor)
shadowColorInput.addEventListener('change', changeShadowColor)
shadowBlurInput.addEventListener('change', changeShadowBlur)
shadowOffsetXInput.addEventListener('change', changeShadowOffsetX)
shadowOffsetYInput.addEventListener('change', changeShadowOffsetY)
clearBtn.addEventListener('click', clearCanvas)
outputJpegBtn.addEventListener('click', () => output('jpeg'))
outputPngBtn.addEventListener('click', () => output('png'))
brushSelector.addEventListener('change', selectBrush)
canvas.isDrawingMode = true
00