Closed7
[キャッチアップ] Fabric.js を Vue3 から使う
概要
- fabric.js を Vue3 で使ってゴニョゴニョする際に自分用メモです
- fabric 自体初めて使うので、そっちに関するメモも多めです
- 知見が溜まったら記事にまとめるかも
セットアップ
vue-cli でひな形作る
preset は vue3 + TypeScript さえあればOKなので適当に
$ vue create project-name
facric 及び型情報のインストール
$ yarn add facric
$ yarn add -D @types/fabric
Hello, Fabric
App.vue
を編集して、 Fabric が最低限動くことを確認する
src/App.vue
<template>
<h1>Hello, Facric!!</h1>
<button @click="add">Add</button>
<div class="wrapper">
<canvas id="canvas" width="600" height="600" />
</div>
</template>
<script lang="ts">
import { computed, defineComponent } from "vue";
import { fabric } from "fabric";
export default defineComponent({
setup() {
const canvas = computed<fabric.Canvas>(() => new fabric.Canvas("canvas"));
const add = () => {
canvas.value.add(
new fabric.Rect({
top: 100,
left: 100,
width: 60,
height: 60,
fill: "red",
})
);
};
return { add };
},
});
</script>
<style scoped>
.wrapper {
width: 600px;
height: 600px;
border: 1px solid;
}
</style>
fe1314df53be1bc79fb66d5549b1b748e2a8c736
良い感じに、ボタンを押すと移動したり拡大縮小できる矩形オブジェクトがキャンバスに描画されるようになった。
LocalStorage で状態を保存、復元する
Canvas
オブジェクトに対して、 JSON.stringify
してあげれば状態をJSONで取得でき、 loadFromJSON
メソッドで復元することができる。
ボタンを適当に追加して
src/App.vue
<template>
<h1>Hello, Fabric!!</h1>
<button @click="add">Add</button>
<button @click="save">Save</button>
<button @click="load">Load</button>
<div class="wrapper">
<canvas id="canvas" width="600" height="600" />
</div>
</template>
save / load の関数を作成
src/App.vue
export default defineComponent({
setup() {
// 中略
const save = () => {
const canvasState = JSON.stringify(canvas.value);
localStorage.setItem("state", canvasState);
};
const load = () => {
const canvasState = localStorage.getItem("state");
canvas.value.loadFromJSON(canvasState, () => console.log("loaded!!"));
};
return { add, save, load };
},
});
9e4d0fb7f8fd59ff6b87c504567d8838c545102b
背景画像を設定する
fabric.Image.fromURL
で、URLから画像を取得できるので、それをキャンバスいっぱいに引き伸ばして微妙がする。(例として zenn のユーザーアイコン画像を使わせてもらってます)
src/App.vue
onMounted(() => {
const imageUrl = 'https://storage.googleapis.com/zenn-user-upload/avatar/845fa75ba8.jpeg'
fabric.Image.fromURL(imageUrl, image => {
image.scaleToWidth(canvas.value.getWidth())
canvas.value.setBackgroundImage(image, canvas.value.renderAll.bind(canvas.value))
})
})
3b72182178b0ac0aac32a0b3f353c4521c52a21e
Kawaii
矩形オブジェクト用のコンポジションを切り出す
ここまでは new fabric.Rect
を使って、初期値が固定の矩形オブジェクトを生成していたが、これをコンポジションの分離する。
まずは丸ごと移動して、 fabric をラップしてくれる形にすることで、コンポーネント側をシンプルにする
src/compositions/useFabric.ts
import { fabric } from 'fabric'
import { IRectOptions } from 'fabric/fabric-impl'
import { computed } from 'vue'
export default function useFabric(canvasId: string) {
const canvas = computed<fabric.Canvas>(() => new fabric.Canvas(canvasId))
const addObject = (object: fabric.Object) => {
canvas.value.add(object)
}
const addRect = (options: IRectOptions) => {
const rect = new fabric.Rect(options)
addObject(rect)
}
const setBackgroundImageFromUrl = (url: string) => {
fabric.Image.fromURL(url, image => {
image.scaleToWidth(canvas.value.getWidth())
canvas.value.setBackgroundImage(image, canvas.value.renderAll.bind(canvas.value))
})
}
const fromJSON = (json: string | null) => {
canvas.value.loadFromJSON(json, () => {})
}
const toJSON = () => {
return JSON.stringify(canvas.value)
}
return { addRect, setBackgroundImageFromUrl, fromJSON, toJSON }
}
src/App.vue
export default defineComponent({
setup() {
const fabric = useFabric('canvas')
onMounted(() => {
const imageUrl = 'https://storage.googleapis.com/zenn-user-upload/avatar/845fa75ba8.jpeg'
fabric.setBackgroundImageFromUrl(imageUrl)
})
const add = () => {
fabric.addRect({ width: 100, height: 100, fill: 'red' })
}
const save = () => {
localStorage.setItem('state', fabric.toJSON())
}
const load = () => {
fabric.fromJSON(localStorage.getItem('state'))
}
return { add, save, load }
}
})
aeb20c5c35d4e037731678778631db6c88313ccb
選択中のオブジェクトを削除する
src/compositions/useFabric.ts
const removeObject = (object: fabric.Object) => {
canvas.value.remove(object)
}
const removeSelectedObject = () => {
removeObject(canvas.value.getActiveObject())
}
このスクラップは2021/04/12にクローズされました