파이널 프로젝트때 사용할 canvas 라이브러리 공부한 내용 정리입니다
fabric은 canvas 위 그림을 객체로 관리하는 라이브러리입니다
// fabric install
$ npm install fabric --save
// 리액트 import
import { fabric } from "fabric";
리액트 상에서 사용법은 다음과 같습니다
1. canvas id 설정
<canvas id='canvas' />
import React, { useState } from 'react';
const [canvas, setCanvas] = useState('');
const initCanvas = () => (
new fabric.Canvas('elementId', { style })
)
import React, { useState, useEffect } from 'react';
useEffect(() => {
setCanvas(initCanvas());
}, []);
import React, { useState, useEffect } from "react";
import { fabric } from "fabric";
function Draw() {
const [canvas, setCanvas] = useState("");
const initCanvas = () =>
new fabric.Canvas("canvas", {
height: 800,
width: 800,
backgroundColor: "gray",
});
useEffect(() => {
setCanvas(initCanvas());
}, []);
return <canvas id="canvas" />;
}
export default Draw;
기본적으로 제공하는 도형객체들입니다
fabric.Circle // 동작안됨
fabric.Ellipse // 동작안됨
fabric.Line
fabric.Polygon // 동작안됨
fabric.Polyline
fabric.Rect // 동작됨
fabric.Triangle // 동작됨
// 사용 예시
let circle = new fabric.Circle({
radius: 20, fill: 'gray', left: 100, top: 200
})
canvas.add(circle); // add로 원하는 도형을 추가해줍니다
// 추가
.add(추가할 객체)
// 삭제
.remove()
// 그룹 내 객체 하나에 접근
.item()
// 그룹 내 모든 객체 반환
.getObjects()
// 뒷배경 설정
.setBackgroundImage('이미지링크', canvas.renderAll.bind(canvas), {스타일})
// ??
.onFpsUpdate = () => {}
canvas에 이미지 불러오는 방법
fabric.image.fromURL
멀터를 사용해서 이미지 업로드하는 코드
const handleImage = (e) => {
const reader = new FileReader();
const file = e.target.files[0];
reader.onload = () => {
new fabric.Image.fromURL(reader.result, (image) => {
image.scale(0.75);
canvas.add(image);
canvas.renderAll();
});
};
reader.readAsDataURL(file);
};
axios로 서버에 이미지 전송하는방법
// 저장 핸들러
const saveHandler = async () => {
if (user.isLogin) {
const canvasData = JSON.stringify(canvas);
const sendData = { ...caseInfo, setting: canvasData };
const imgdata = canvas.toDataURL("image/png", 1.0);
let file = base64toFile(imgdata);
let formdata = new FormData();
formdata.append("picture", file);
if (review.caseInfo.id) {
formdata.append("caseId", review.caseInfo.id);
formdata.append("phondId", review.caseInfo.phoneId);
formdata.append("price", review.caseInfo.price);
formdata.append("setting", canvasData);
} else {
for (let el in sendData) {
formdata.append(el, sendData[el]);
}
}
await axios
.post(`${process.env.REACT_APP_API_URL}locker`, formdata, {
withCredentials: true,
header: { "Content-Type": "multipart/form-data" },
})
.then((el) => {
if (el.data.message === "새로운 저장") {
dispatch(handleAlertModal("새롭게 저장되었습니다"));
} else if (el.data.message === "ok") {
dispatch(
handleConfirmModal(
"저장이 완료되었습니다",
0,
"보관함으로 이동 하시겠습니까?"
)
);
}
});
} else {
dispatch(handleAlertModal("로그인 해주세요"));
reverseBoo();
}
};
hex, RGB, RGBA 다 지원합니다
new fabric.Color('#f55');
new fabric.Color('#123123');
new fabric.Color('356735');
new fabric.Color('rgb(100,0,100)');
new fabric.Color('rgba(10, 20, 30, 0.5)');
기본적인 css정도는 다 제공되는 것 같습니다
Multiline support: 네이티브 텍스트의 경우는 새로운 라인을 지원하지 않았습니다.
Text alignment: Left, Center. right 등 멀티라인 텍스트에 대한 정렬을 제공합니다.
Text background: 백그라운드 역시 텍스트 정렬을 지원합니다.
Text decoration: 텍스트 장식을 지원합니다.
Line height: 멀티라인에 대한 높이 간격 설정에 유용합니다.
Char spacing: 문자 간격을 조정할 수 있습니다.
Subranges: 텍스트 객체의 하위 범주에 대한 색상 및 속성 지정이 가능합니다.
Multibyte: 이모티콘도 지원합니다.
On canvas editing: 대화형 클래스를 통해 캔버스에서 직접 편집이 가능합니다.
const text = new fabric.IText('hello world', { left: 100, top: 100, fontFamily: 'sans-serif' });
canvas.add(text);
캔버스에서 일어나는 다양한 행동들이 발생하는 순간에 활용됩니다
mouse:down 마우스 눌렀을때
object:added 캔버스에 객체가 추가됬을때
after:render 캔버스 전체가 다시 렌더링 됬을때
const canvas = new fabric.Canvas('...');
canvas.on('mouse:down', function(options) {
console.log(options.e.clientX, options.e.clientY);
});
아래처럼 객체에 직접 붙힐수도 있습니다
rect.on('selected', function() {
console.log('selected a rectangle');
});
여러객체들을 단일객체로 묶은 것입니다
const circle = new fabric.Circle({
radius: 100,
fill: '#eef',
});
var text = new fabric.Text({
fontSize: 30,
});
var group = new fabric.Group([ circle, text ], {
left: 150,
top: 100,
});
canvas.add(group);
위 처럼 3개의 객체를 하나로 묶고
group.item(0).setFill('red');
group.item(1).set({
text: 'trololo',
fill: 'white'
});
item()을 사용하여 개별 객체를 건드릴수있습니다
canvas.getActiveObjects()
활성화된 객체의 폰트나, 사이즈, 색상등을 바꿀때 사용하는 함수로 추측됨
const item = canvas.getActiveObjects();
item.set({ fontSize: e.target.value })
canvas.renderAll();
setFontSize(e.target.value);
만든 캔버스를 이미지로 내보낼 수있는 옵션이 존재하지만 그만큼 성능에 영향을 미치게됩니다
그래서 텍스트로 용량 최적화를 시켜 보내는데 필요한 것이 직렬화/역직렬화입니다
아래는 대표적인 뼈대인 toObject, toJSON를 사용한 간단한 예입니다, toDataURL('png')도 있습니다
const canvas = new fabric.Canvas('c');
JSON.stringify(canvas); // '{"objects": [], "background": "rgba(0, 0, 0, 0)"}
또한 toSVG로 직렬화하는 방법이 있습니다
canvas.add(new fabric.Rect({
left: 30,
top: 30,
height: 30,
width: 30,
fill: 'blue'
}));
console.log(canvas.toSVG());
캔버스에 우리가 직렬화 시킨것을 로드하려면 두가지를 사용할 수 있습니다
// fromJSON
// SG parser
fabric.loadSVGFromString('...', function(objects, options) {
const obj = fabric.util.groupSVGElements(objects, options);
canvas.add(obj).renderAll();
});
// 캔버스 반응형 이벤트
const handleResizeEvent = () => {
if (document.body.clientWidth <= 768) {
canvas.setDimensions({
width: 600,
height: 600,
});
}
if (document.body.clientWidth <= 425) {
canvas.setDimensions({
width: 200,
height: 400,
});
}
canvas.renderAll();
};
캔버스에서 사용
canvas.on('mouse:down', (event) => {
if(event.button === 1) {
console.log("left click");
}
if(event.button === 2) {
console.log("middle click");
}
if(event.button === 3) {
console.log("right click");
}
}
객체에서 사용
object.on('mousedown', (event) => {
if(event.button === 1) {
console.log("left click");
}
if(event.button === 2) {
console.log("middle click");
}
if(event.button === 3) {
console.log("right click");
}
}
const pointer = new fabric.Point(
canvas.getPointer(e.e).x,
canvas.getPointer(e.e).y
);
console.log(pointer);
fabric github: https://github.com/fabricjs/fabric.js
fabric-history github: https://github.com/lyzerk/fabric-history
JSDoc: http://fabricjs.com/docs/fabric.StaticCanvas.html
fabric 기초 생성: https://aprilescobar.medium.com/part-1-fabric-js-on-react-fabric-canvas-e4094e4d0304
fabric 사용법: https://itinerant.tistory.com/156
fabric all: https://medium.com/@seohyoda/fabric-js-%EC%9E%85%EB%AC%B8-part-1-78dd390536cf
canvas 반응형 관련 정보: https://www.python2.net/questions-1339788.htm