Files
2025-07-02 14:13:16 +09:00

262 lines
8.8 KiB
JavaScript

//===============================================================================
// #region Fabric.js 캔버스 텍스트 및 이미지 삽입 관련 이벤트 및 함수
//===============================================================================
/** 이미지 업로드 변경 이벤트: 선택한 이미지를 Fabric 캔버스에 추가 */
$('#canvas-image-upload').change(function (event) {
const files = event.target.files;
for (let i = 0; i < files.length; i++) {
const file = files[i];
if (file.type.startsWith('image/')) {
const reader = new FileReader();
reader.onload = function (e) {
fabric.Image.fromURL(e.target.result, function (img) {
// 이미지 중앙 배치 및 캔버스에 추가
img.set({
left: fabricCanvas.width / 2 - img.width / 2,
top: fabricCanvas.height / 2 - img.height / 2,
selectable: true
});
fabricCanvas.add(img);
fabricCanvas.renderAll();
});
}
reader.readAsDataURL(file);
} else {
alert('이미지 파일을 선택해주세요.');
}
}
// 파일 입력 초기화
$('#canvas-image-upload').val('');
});
/** 텍스트 삽입 버튼 클릭 이벤트: 사용자 입력 텍스트를 Fabric 캔버스에 IText 객체로 추가 */
$('#canvas-insert-text-btn').click(function () {
const text = prompt("추가할 텍스트를 입력하세요:", "새 텍스트");
if (text) {
const itext = new fabric.IText(text, {
left: fabricCanvas.width / 2,
top: fabricCanvas.height / 2,
fontSize: 20,
fill: '#000000',
selectable: true,
objectCaching: false
});
fabricCanvas.add(itext);
fabricCanvas.setActiveObject(itext);
}
});
/** 공용 함수: 부분 선택이 있으면 부분만, 없으면 전체 텍스트에 스타일 토글 */
function toggleCanvasTextStyle(styleName, toggleValues) {
const activeObject = fabricCanvas.getActiveObject();
if (!activeObject || activeObject.type !== 'i-text') return;
// 선택 범위 가져오기
const start = activeObject.selectionStart;
const end = activeObject.selectionEnd;
// 전체 텍스트에 적용하는 경우
if (start === end) {
const current = activeObject[styleName];
// 현재 스타일값을 토글
const newVal = (current === toggleValues[0]) ? toggleValues[1] : toggleValues[0];
activeObject.set(styleName, newVal);
} else {
// 부분 선택이 있는 경우
const currentStyles = activeObject.getSelectionStyles(start, end);
let allSame = true;
for (let i = 0; i < currentStyles.length; i++) {
if (currentStyles[i][styleName] !== toggleValues[0]) {
allSame = false;
break;
}
}
// 스타일 토글 값 결정
const newVal = allSame ? toggleValues[1] : toggleValues[0];
activeObject.setSelectionStyles({
[styleName]: newVal
}, start, end);
}
fabricCanvas.renderAll();
}
/** 캔버스 굵게 버튼 클릭 이벤트 */
$('#canvas-bold-btn').click(function () {
// fontWeight를 'bold' <-> 'normal' 로 토글
toggleCanvasTextStyle('fontWeight', ['bold', 'normal']);
});
/** 캔버스 기울임 버튼 클릭 이벤트 */
$('#canvas-italic-btn').click(function () {
// fontStyle을 'italic' <-> 'normal' 로 토글
toggleCanvasTextStyle('fontStyle', ['italic', 'normal']);
});
/** 캔버스 밑줄 버튼 클릭 이벤트 */
$('#canvas-underline-btn').click(function () {
const activeObject = fabricCanvas.getActiveObject();
if (!activeObject || activeObject.type !== 'i-text') return;
const start = activeObject.selectionStart;
const end = activeObject.selectionEnd;
if (start === end) {
// 전체 텍스트 밑줄 토글
activeObject.set('underline', !activeObject.get('underline'));
} else {
// 부분 선택 영역에 대해 밑줄 토글
const currentStyles = activeObject.getSelectionStyles(start, end);
let allUnderlined = true;
for (let i = 0; i < currentStyles.length; i++) {
if (!currentStyles[i].underline) {
allUnderlined = false;
break;
}
}
const newVal = !allUnderlined;
activeObject.setSelectionStyles({
underline: newVal
}, start, end);
}
fabricCanvas.renderAll();
});
/** 캔버스 텍스트 색상 변경 이벤트 */
$('#canvas-text-color-picker').on('input', function () {
const color = $(this).val();
applyCanvasTextColor(color);
});
/** 캔버스 글자 크기 변경 이벤트: 직접 입력된 값 적용 */
$('#canvas-font-size-btn').change(function () {
const fontSize = parseInt($(this).val(), 10);
const activeObject = fabricCanvas.getActiveObject();
if (activeObject && activeObject.type === 'i-text') {
activeObject.set('fontSize', fontSize);
fabricCanvas.renderAll();
}
});
/** 펜 설정 토글 버튼 클릭 이벤트 (옵션 예시) */
$('#pen-settings-btn').click(function () {
$('#pen-settings').toggle();
});
/** 펜 색상 변경 이벤트 */
$('#pen-color-picker').change(function () {
if (fabricCanvas.isDrawingMode) {
fabricCanvas.freeDrawingBrush.color = $(this).val();
}
});
/** 펜 두께 변경 이벤트 */
$('#pen-thickness').change(function () {
if (fabricCanvas.isDrawingMode) {
fabricCanvas.freeDrawingBrush.width = parseInt($(this).val(), 10) || 2;
}
});
/** 드로잉 모드 토글 버튼 클릭 이벤트 */
$('#toggle-draw-btn').click(function () {
if (fabricCanvas) {
isDrawingMode = !isDrawingMode;
fabricCanvas.isDrawingMode = isDrawingMode;
if (isDrawingMode) {
$(this).addClass('on');
$('#pen-settings').show();
// 새로운 PencilBrush 설정 및 기본 속성 적용
fabricCanvas.freeDrawingBrush = new fabric.PencilBrush(fabricCanvas);
fabricCanvas.freeDrawingBrush.color = $('#pen-color-picker').val();
fabricCanvas.freeDrawingBrush.width = parseInt($('#pen-thickness').val(), 10) || 2;
fabricCanvas.freeDrawingCursor = 'url("image/svg/pen-btn.svg") 3 15, auto';
console.log('드로잉 모드 활성');
} else {
$(this).removeClass('on');
$('#pen-settings').hide();
fabricCanvas.freeDrawingCursor = 'default';
console.log('드로잉 비활성');
}
}
});
/** 캔버스 이미지 삽입 버튼 클릭 이벤트: 이미지 업로드 창 트리거 */
$('#canvas-insert-image-btn').click(function () {
$('#canvas-image-upload').click();
});
/** 캔버스 텍스트 색상 적용 함수 */
function applyCanvasTextColor(color) {
const obj = fabricCanvas.getActiveObject();
if (!obj || obj.type !== 'i-text') return;
const s = obj.selectionStart;
const e = obj.selectionEnd;
if (s < e) {
// 부분 선택 구간만 색상 변경
obj.setSelectionStyles({
fill: color
}, s, e);
} else {
// 전체 텍스트 색상 변경
obj.set('fill', color);
}
// 즉시 반영
obj.dirty = true;
obj.setCoords();
fabricCanvas.renderAll();
}
/** 캔버스 텍스트 배경색 변경 함수 */
function applyCanvasBackgroundColor(color) {
const obj = fabricCanvas.getActiveObject();
if (!obj || obj.type !== 'i-text') return;
const s = obj.selectionStart;
const e = obj.selectionEnd;
if (s < e) {
// 부분 선택 구간만 배경색 변경
obj.setSelectionStyles({
backgroundColor: color
}, s, e);
} else {
// 전체 텍스트 배경색 변경
obj.set('backgroundColor', color);
}
// 즉시 반영
obj.dirty = true;
obj.setCoords();
fabricCanvas.renderAll();
}
/** 캔버스 폰트 크기 적용 함수 */
function applyCanvasFontSize(fontSize) {
const obj = fabricCanvas.getActiveObject();
if (!obj || obj.type !== 'i-text') return;
const s = obj.selectionStart;
const e = obj.selectionEnd;
if (s < e) {
// 부분 선택 구간만 폰트 크기 변경
obj.setSelectionStyles({
fontSize: fontSize
}, s, e);
} else {
// 전체 텍스트 폰트 크기 변경
obj.set('fontSize', fontSize);
}
// 즉시 반영
obj.dirty = true;
obj.setCoords();
fabricCanvas.renderAll();
}
//===============================================================================
// #endregion Fabric.js 캔버스 텍스트 및 이미지 삽입 관련
//===============================================================================