背景
最近在投递简历的时候发现,很多HR在哪儿问,你会不会fabric.js啊;我说我暂时没看过,但是应该不难,看哈文档就能上手了。HR跟我说:“那你可能不太适合我们,祝你早日找到工作。”
咦,我这暴脾气…
写了一个简单的教程,大家可以根据到学习学习。
技术栈
我是用vite + vue3 搭建的项目。切记这是vue3,因为这儿在后续会出现一个问题。
绘制一个矩形
绘制一个简单的矩形。
1
2<canvas id="canvas" width="400" height="400"></canvas>
3
4import { fabric } from 'fabric';
5
6canvas.value = new fabric.Canvas('canvas', {
7
8
9 preserveObjectStacking: true,
10}),
11
12const rect: any = new fabric.Rect({
13 left: 100,
14 top: 100,
15 fill: 'red',
16 width: 120,
17 height: 120,
18 z: 10,
19});
20
21
22canvas.value.add(rect);
注意注意注意…
如果你用的是vue3搭建的项目,这样写可能会有问题。我查了很多资料才发现,需要这样修改,这是示例:
1import { markRaw } from 'vue';
2import * as fabric from 'fabric';
3
4canvas.value = markRaw(
5 new fabric.Canvas('canvas', {
6
7
8 preserveObjectStacking: true,
9 }),
10);
绘制圆形、三角形等等原理都是一样的,大家可以自己学,并且去看看官方网站的参数,有许多有用的参数比如: angle(角度),opacity(透明度)等等。官方文档-只有英文 | 中文文档,如果你们有更好的可以推荐我修改 | 可以参考文档
图片的渲染方式
既然是canvas那么肯定是要用到图片的,而且可能有很多操作图片的情况,那我们怎么添加图片呢?
【第一种方法:不推荐】
1
2<input
3 id="avatar-upload-input"
4 style="display: none"
5 accept="image/png, image/jpeg, image/jpg"
6 type="file"
7 @change="changeInput"
8/>
9
10
11const changeInput = (event: any) => {
12
13 let file = event.target.files[0];
14
15 const reader = new FileReader();
16
17 if (file) {
18 reader.onload = (e: any) => {
19 console.log(e.target.result);
20 const dataUrl = e.target.result;
21 const imgElement = document.createElement('img');
22 imgElement.src = dataUrl;
23 imgElement.onload = () => {
24 const img: any = renderImages(dataUrl);
25 canvas.value.add(img);
26 img.scaleToWidth(400);
27
28 canvas.value.renderAll();
29 };
30 };
31 }
32
33 reader.readAsDataURL(file);
34};
35
36const renderImages = (result: string) => {
37 const imgElement = document.createElement('img');
38 imgElement.src = result;
39
40 return new fabric.Image(imgElement, {
41 left: 0,
42 top: 0,
43 angle: 0,
44 opacity: 1,
45 centeredScaling: true,
46 crossOrigin: 'Anonymous',
47
48 hasControls: false,
49 hasBorders: false,
50 selectable: false,
51 lockMovementX: false,
52 lockMovementY: false,
53 lockScalingX: false,
54 lockScalingY: false,
55 });
56};
【第二种方法:推荐】
通过上传图片获取到的base64然后通过Image加载图片。
1<input
2 id="avatar-upload-inputs"
3 style="display: none"
4 accept="image/png, image/jpeg, image/jpg"
5 type="file"
6 @change="changeInputs"
7/>
8
9const changeInputs = (event: any) => {
10
11 let file = event.target.files[0];
12
13 const reader = new FileReader();
14
15 if (file) {
16 reader.onload = (e: any) => {
17 console.log(e.target.result);
18 const dataUrl = e.target.result;
19 fabric.Image.fromURL(dataUrl).then((img: any) => {
20 img.scaleToWidth(400);
21 canvas.value.add(img);
22 });
23 };
24 }
25
26 reader.readAsDataURL(file);
27};
【第三种方式:推荐】
加载静态图片。
1const selectProfilePicture = (picture: string) => {
2 const img: any = canvas.value.getObjects()[0];
3
4 if (img) {
5 canvas.value.remove(img);
6 fabric.Image.fromURL(getImageUrl(picture)).then((img: any) => {
7 img.scaleToWidth(400);
8 canvas.value.add(img);
9 });
10 } else {
11 fabric.Image.fromURL(getImageUrl(picture)).then((img: any) => {
12 img.scaleToWidth(400);
13 canvas.value.add(img);
14 });
15 }
16};
17
18const getImageUrl = (name: string) => {
19 return new URL(`../images/${name}`, import.meta.url).href;
20}
如果想修改一些参数的话,可以用一下方式。
1fabric.Image.fromURL(getImageUrl(picture)).then((img: any) => {
2 img.scaleToWidth(400);
3 img.set({
4 left: 100,
5 top: 100,
6 });
7 canvas.value.add(img);
8});
移出对象元素
1const img: any = canvas.value.getObjects()[0];
2
3if (img) {
4 canvas.value.remove(img);
5}
总结
以上是一些基本,操作;后续有时间学习会更新专栏。大家可以持续关注。
个人笔记记录 2021 ~ 2025