import { addDistanceTextToPolygon, getDistance } from '@/util/canvas-util' import { useCanvas } from '@/hooks/useCanvas' import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { useEffect } from 'react' export default function Roof() { const { canvas, addShape, handleUndo, handleRedo, handleClear, handleCopy, handleDelete, handleSave, handlePaste, handleRotate, attachCustomControlOnPolygon, saveImage, handleFlip, } = useCanvas('canvas') useEffect(() => { let circle = new fabric.Circle({ radius: 40, fill: 'rgba(200, 0, 0, 0.3)', originX: 'center', originY: 'center', }) let text = new fabric.Textbox('AJLoveChina', { originX: 'center', originY: 'center', textAlign: 'center', fontSize: 12, }) let group = new fabric.Group([circle, text], { left: 100, top: 100, originX: 'center', originY: 'center', }) group.on('mousedblclick', () => { // textForEditing is temporary obj, // and will be removed after editing console.log(text.type) let textForEditing = new fabric.Textbox(text.text, { originX: 'center', originY: 'center', textAlign: text.textAlign, fontSize: text.fontSize, left: group.left, top: group.top, }) // hide group inside text text.visible = false // note important, text cannot be hidden without this group.addWithUpdate() textForEditing.visible = true // do not give controls, do not allow move/resize/rotation on this textForEditing.hasConstrols = false // now add this temporary obj to canvas canvas.add(textForEditing) canvas.setActiveObject(textForEditing) // make the cursor showing textForEditing.enterEditing() textForEditing.selectAll() // editing:exited means you click outside of the textForEditing textForEditing.on('editing:exited', () => { let newVal = textForEditing.text let oldVal = text.text // then we check if text is changed if (newVal !== oldVal) { text.set({ text: newVal, visible: true, }) // comment before, you must call this group.addWithUpdate() // we do not need textForEditing anymore textForEditing.visible = false canvas?.remove(textForEditing) // optional, buf for better user experience canvas?.setActiveObject(group) } }) }) canvas?.add(group) }, [canvas]) const addRect = () => { const rect = new fabric.Rect({ height: 200, width: 200, top: 10, left: 10, opacity: 0.4, fill: randomColor(), stroke: 'red', name: uuidv4(), }) addShape(rect) } const addHorizontalLine = () => { const { x1, y1, x2, y2 } = { x1: 20, y1: 100, x2: 220, y2: 100 } /** * 시작X,시작Y,도착X,도착Y 좌표 */ const horizontalLine = new fabric.Line([x1, y1, x2, y2], { name: uuidv4(), stroke: 'red', strokeWidth: 3, selectable: true, }) const text = new fabric.Text(getDistance(x1, y1, x2, y2).toString(), { fontSize: 20, left: (x2 - x1) / 2, top: y1 - 20, }) const group = new fabric.Group([horizontalLine, text], { left: 20, top: 20, }) // addShape(horizontalLine) addShape(group) console.log(JSON.stringify(canvas)) } const addVerticalLine = () => { const verticalLine = new fabric.Line([10, 10, 10, 100], { name: uuidv4(), stroke: 'red', strokeWidth: 3, selectable: true, }) addShape(verticalLine) } const addTriangle = () => { const triangle = new fabric.Triangle({ name: uuidv4(), top: 50, left: 50, width: 100, stroke: randomColor(), strokeWidth: 3, }) addShape(triangle) } const addTrapezoid = () => { const trapezoid = new fabric.Polygon( [ { x: 100, y: 100 }, // 좌상단 { x: 500, y: 100 }, // 우상단 { x: 750, y: 700 }, // 우하단 { x: 250, y: 400 }, // 좌하단 ], { name: uuidv4(), stroke: 'red', opacity: 0.4, strokeWidth: 3, selectable: true, objectCaching: false, }, ) attachCustomControlOnPolygon(trapezoid) const group = addDistanceTextToPolygon(trapezoid) addGroupClickEvent(group) canvas?.add(group) canvas?.renderAll() } // group에 클릭 이벤트를 추가하여 클릭 시 group을 제거하고 object들만 남기는 함수 function addGroupClickEvent(group) { group.on('selected', (e) => { console.log(e) }) group.on('mousedblclick', (e) => { // textForEditing is temporary obj, // and will be removed after editing const pointer = canvas?.getPointer(e.e) // 마우스 클릭 위치 가져오기 let minDistance = Infinity let closestTextbox = null const groupPoint = group.getCenterPoint() group.getObjects().forEach(function (object) { if (object.type === 'textbox') { // 객체가 TextBox인지 확인 const objectCenter = object.getCenterPoint() // TextBox 객체의 중심점 가져오기 const dx = objectCenter.x + groupPoint.x - pointer.x const dy = objectCenter.y + groupPoint.y - pointer.y const distance = Math.sqrt(dx * dx + dy * dy) // 마우스 클릭 위치와 TextBox 객체 사이의 거리 계산 if (distance < minDistance) { // 가장 짧은 거리를 가진 TextBox 객체 찾기 minDistance = distance closestTextbox = object } } }) let textForEditing = new fabric.Textbox(closestTextbox.text, { originX: 'center', originY: 'center', textAlign: closestTextbox.textAlign, fontSize: closestTextbox.fontSize, left: closestTextbox.left + groupPoint.x, top: closestTextbox.top + groupPoint.y, }) // hide group inside text closestTextbox.visible = false // note important, text cannot be hidden without this group.addWithUpdate() textForEditing.visible = true // do not give controls, do not allow move/resize/rotation on this textForEditing.hasConstrols = false // now add this temporary obj to canvas canvas?.add(textForEditing) canvas?.setActiveObject(textForEditing) // make the cursor showing textForEditing?.enterEditing() textForEditing?.selectAll() // editing:exited means you click outside of the textForEditing textForEditing?.on('editing:exited', () => { let newVal = textForEditing.text // then we check if text is changed closestTextbox.set({ text: newVal, visible: true, }) // comment before, you must call this group.addWithUpdate() // we do not need textForEditing anymore textForEditing.visible = false canvas?.remove(textForEditing) // optional, buf for better user experience canvas?.setActiveObject(group) }) }) } // IText를 수정할 때 해당 값을 길이로 갖는 다른 polygon을 생성하고 다시 그룹화하는 함수 function addTextModifiedEvent(text, polygon, index) { text.on('editing:exited', function () {}) } const randomColor = () => { return '#' + Math.round(Math.random() * 0xffffff).toString(16) } return ( <>
) }