今天就來複習昨天我們學到的 Fabricjs 繪畫功能來做一個簡易的小畫家吧。
透過 Fabricjs 我們可以相當快速又簡單的做出一個類似畫板的功能,讓使用者能夠隨意的切換畫筆顏色、粗細、陰影等樣式。
最後會在特別介紹 Fabricjs 將 canvas 轉換成圖片的功能。
先來看看做出來的結果
const $ = (id) => document.getElementById(id)
const drawingOptionArea = $('drawingOptionArea')
const clearBtn = $('clear')
const modeBtn = $('mode')
const lineWidthInput = $('lineWidthInput')
const lineWidthValue = $('lineWidthValue')
const lineColorInput = $('lineColorInput')
...略
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
}
...略
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 的編碼,再透過瀏覽器下載到本機,且可傳入一些基本設定值。
format
: 'image/png' | 'image/jpeg''image/'
當作前墜,也就是 'image/png' | 'image/jpeg'
這樣輸出就沒有問題了。top、left、width、height
這幾個參數用來設定你要輸出畫布的大小multiplier
這個參數可以縮放你所輸出的 canvas ,參數為縮放倍率 ex: 0.5 輸出大小為原本一半quality
可以調整輸出圖片的質量,範圍為 0..~1function 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)
}
<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>
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
}
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
將昨天所學的 fabricjs 筆刷功能,配合 html input 來控制畫筆樣式。
將畫完的結果匯出成圖檔。匯出圖檔的詳細說明。