昨天實作了 Particles.js ,今天就來玩玩 Fabric.js !大家還記得前天對於 Fabric.js 的介紹嗎?不記得也沒關係只要掌握兩件事,一是 Fabric.js 提供了許多 API 讓使用者可以直接在畫布上進行操作,例如選取、縮放、旋轉、變色等,此外 Fabric.js 也可以把 Canvas 轉成序列化的格式,包含 Json 和 svg,這兩個特點今天都會示範唷!
一樣的我們可以直接安裝 fabricjs-react 的套件,因為我的專案內有用到 fabric,所以我也一併安裝了 fabric.js 和他的 type 型別。
npm install --save fabricjs-react fabric react react-dom
npm install fabric --save
npm install --save @types/fabric
FabricJSEditor
提供了許多強大的 API,讓我們不用再去針對 canvas 寫程式繪圖,可以直接調用以下的 API 完成許多繪圖功能,如下圖是 FabricJSEditor
包含的功能,有新增圓形、矩形、線條、文字、填色、邊線顏色等等。
export interface FabricJSEditor {
canvas: fabric.Canvas;
addCircle: () => void;
addRectangle: () => void;
addLine: () => void;
addText: (text: string) => void;
updateText: (text: string) => void;
deleteAll: () => void;
deleteSelected: () => void;
fillColor: string;
strokeColor: string;
setFillColor: (color: string) => void;
setStrokeColor: (color: string) => void;
zoomIn: () => void;
zoomOut: () => void;
}
以下程式碼當中可以看到主要的幾個 API 調用方式都非常簡單,直接以 onClick 監聽後呼叫對應的 API,就可以完成我們想要的對應的功能,這邊特別分享幾個比較需要注意的設計:
當選擇的是已經寫好的文字,那就會更新新的 Input value,若不是則會直接新增一個新的文字
const handleAddText = () => {
if (selectedObjects?.length) {
return editor?.updateText(text);
}
editor?.addText(text);
};
我們可以透過 input
type=color 的方式讓使用者選取顏色,並以 onChange
作為選擇的監聽,選好顏色後再呼叫 setFillColor()
,記得這裡只有被選擇的或是直接新增的會變更顏色
const handleFillColor = () => {
editor?.setFillColor(fillColor);
};
<input
style={{ width: '40px', height: '40px' }}
type="color"
value={strokeColor || editor?.strokeColor}
onChange={(e) => setStrokeColor(e.target.value)}
/>
<button className="button-16" onClick={handleAddStrokeColor}>
Set Stroke Color
</button>
a. 此處為了要讓樣式好看,所以我以 <label>
包裝,並讓原生的 type="file" 的樣式直接消失,當然如果想直接使用原生樣式,這裡就不需要 display: none
與包一個 <label>
b. 因為可以上傳多個檔案,因此 handleUploadImage()
當中有以 map 的概念去新增每一個檔案,並且全部渲染
const handleUploadImage = (e: any) => {
const image = e.target.files[0];
fabric.Image.fromURL(URL.createObjectURL(image), (img) => {
editor?.canvas.add(img);
editor?.canvas.renderAll();
});
};
<label className="button-16">
<input type="file" style={{ display: 'none' }} onChange={handleUploadImage} />
<div style={{ paddingTop: '5px' }}>Upload Image</div>
</label>
前面有提到 Fabric.js 可以很輕鬆的把 Canvas 轉成序列化的格式,在這個範例的最後我也有加上這個功能,當有物件被選取到時就顯示出該物件的 json 格式資料。
<pre>{selectedObjects?.length !== 0 && JSON.stringify(selectedObjects)}</pre>
完整專案程式碼之後會一起釋出 github 唷~~