diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 9604ec7c..55765279 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -11,6 +11,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { direction: null, idx: 0, area: 0, + children: [], initialize: function (points, options, canvas) { this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? false }) if (options.id) { @@ -122,6 +123,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { lockRotation: true, lockScalingX: true, lockScalingY: true, + parent: this, name: 'lengthText', }) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 28a7d84a..c5093f91 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -17,6 +17,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { cells: [], parentId: null, innerLines: [], + children: [], initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { @@ -195,6 +196,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { lockScalingY: true, idx: i, name: 'lengthText', + parent: this, }) this.texts.push(text) @@ -271,6 +273,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { name: 'cell', idx: idx, parentId: this.id, + parent: this, }) idx++ diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index abcb22cc..42fe035d 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -179,25 +179,6 @@ export function useCanvas(id) { }) } - /** - * 선택한 도형을 삭제한다. - */ - const handleDelete = () => { - const targets = canvas?.getActiveObjects() - if (targets?.length === 0) { - alert('삭제할 대상을 선택해주세요.') - return - } - - if (!confirm('정말로 삭제하시겠습니까?')) { - return - } - - targets?.forEach((target) => { - canvas?.remove(target) - }) - } - /** * 페이지 내 캔버스 저장 * todo : 현재는 localStorage에 그냥 저장하지만 나중에 변경해야함 @@ -469,7 +450,6 @@ export function useCanvas(id) { handleUndo, handleRedo, handleCopy, - handleDelete, handleSave, handlePaste, handleRotate, diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index ea5256e6..89a15b3a 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -12,16 +12,112 @@ export function useCanvasEvent() { // 기본적인 이벤트 필요시 추가 const attachDefaultEventOnCanvas = () => { removeEventOnCanvas() - canvas?.on('object:added', onChange) - canvas?.on('object:added', addEventOnObject) - canvas?.on('object:modified', onChange) - canvas?.on('object:removed', onChange) + canvas?.on('object:added', objectEvent.onChange) + canvas?.on('object:added', objectEvent.addEvent) + canvas?.on('object:modified', objectEvent.onChange) + canvas?.on('object:removed', objectEvent.onChange) canvas?.on('selection:cleared', selectionEvent.cleared) canvas?.on('selection:created', selectionEvent.created) canvas?.on('selection:updated', selectionEvent.updated) canvas?.on('object:added', () => { document.addEventListener('keydown', handleKeyDown) }) + canvas?.on('object:removed', objectEvent.removed) + } + + const objectEvent = { + onChange: (e) => { + const target = e.target + if (target) { + // settleDown(target) + } + }, + addEvent: (e) => { + const target = e.target + + if (target.type === 'QPolygon' || target.type === 'QLine') { + const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText') + textObjs.forEach((obj) => { + obj.bringToFront() + }) + } + + if (target.name === 'cell') { + target.on('mousedown', () => { + if (target.get('selected')) { + target.set({ selected: false }) + target.set({ fill: '#BFFD9F' }) + } else { + target.set({ selected: true }) + target.set({ fill: 'red' }) + } + canvas?.renderAll() + }) + } + + if (target.name === 'trestle') { + target.on('mousedown', () => { + if (target.defense === 'north') { + alert('북쪽은 선택 불가합니다.') + return + } + if (target.get('selected')) { + target.set({ strokeWidth: 1 }) + target.set({ strokeDashArray: [5, 5] }) + target.set({ selected: false }) + } else { + target.set({ strokeWidth: 5 }) + target.set({ strokeDashArray: [0, 0] }) + target.set({ selected: true }) + } + canvas?.renderAll() + }) + } + + if (target.name === 'lengthText') { + const x = target.left + const y = target.top + target.on('selected', (e) => { + Object.keys(target.controls).forEach((controlKey) => { + target.setControlVisible(controlKey, false) + }) + }) + target.on('moving', (e) => { + if (target.parentDirection === 'left' || target.parentDirection === 'right') { + const minX = target.minX + const maxX = target.maxX + + if (target.left <= minX) { + target.set({ left: minX, top: y }) + } else if (target.left >= maxX) { + target.set({ left: maxX, top: y }) + } else { + target.set({ top: y }) + } + } else if (target.parentDirection === 'top' || target.parentDirection === 'bottom') { + const minY = target.minY + const maxY = target.maxY + + if (target.top <= minY) { + target.set({ left: x, top: minY }) + } else if (target.top >= maxY) { + target.set({ left: x, top: maxY }) + } else { + target.set({ left: x }) + } + } + canvas?.renderAll() + }) + } + }, + removed: (e) => { + const whiteList = ['mouseLine', 'guideLine'] + + if (whiteList.includes(e.target.name)) { + return + } + console.log('removed', e) + }, } const selectionEvent = { @@ -38,146 +134,15 @@ export function useCanvasEvent() { }, } - const onChange = (e) => { - const target = e.target - if (target) { - // settleDown(target) - } - } - const removeEventOnCanvas = () => { canvas?.off('object:added') canvas?.off('object:modified') canvas?.off('object:removed') - canvas?.off('object:added') canvas?.off('selection:cleared') canvas?.off('selection:created') canvas?.off('selection:updated') } - const addEventOnObject = (e) => { - const target = e.target - - if (target.type === 'QPolygon' || target.type === 'QLine') { - const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText') - textObjs.forEach((obj) => { - obj.bringToFront() - }) - } - - if (target.name === 'cell') { - target.on('mousedown', () => { - if (target.get('selected')) { - target.set({ selected: false }) - target.set({ fill: '#BFFD9F' }) - } else { - target.set({ selected: true }) - target.set({ fill: 'red' }) - } - canvas?.renderAll() - }) - } - - if (target.name === 'trestle') { - target.on('mousedown', () => { - if (target.defense === 'north') { - alert('북쪽은 선택 불가합니다.') - return - } - if (target.get('selected')) { - target.set({ strokeWidth: 1 }) - target.set({ strokeDashArray: [5, 5] }) - target.set({ selected: false }) - } else { - target.set({ strokeWidth: 5 }) - target.set({ strokeDashArray: [0, 0] }) - target.set({ selected: true }) - } - canvas?.renderAll() - }) - } - - if (target.name === 'lengthText') { - const x = target.left - const y = target.top - target.on('selected', (e) => { - Object.keys(target.controls).forEach((controlKey) => { - target.setControlVisible(controlKey, false) - }) - }) - target.on('moving', (e) => { - if (target.parentDirection === 'left' || target.parentDirection === 'right') { - const minX = target.minX - const maxX = target.maxX - - if (target.left <= minX) { - target.set({ left: minX, top: y }) - } else if (target.left >= maxX) { - target.set({ left: maxX, top: y }) - } else { - target.set({ top: y }) - } - } else if (target.parentDirection === 'top' || target.parentDirection === 'bottom') { - const minY = target.minY - const maxY = target.maxY - - if (target.top <= minY) { - target.set({ left: x, top: minY }) - } else if (target.top >= maxY) { - target.set({ left: x, top: maxY }) - } else { - target.set({ left: x }) - } - } - canvas?.renderAll() - }) - } - } - - // 마우스 가로, 세로선 그리기 - const drawMouseLines = (e) => { - // 현재 마우스 포인터의 위치를 가져옵니다. - const pointer = canvas?.getPointer(e.e) - - // 기존에 그려진 가이드라인을 제거합니다. - removeMouseLines() - - if (canvas?.getActiveObject()) { - return - } - - // 가로선을 그립니다. - const horizontalLine = new fabric.Line([0, pointer.y, canvasSize.horizontal, pointer.y], { - stroke: 'black', - strokeWidth: 1, - selectable: false, - name: 'mouseLine', - }) - - // 세로선을 그립니다. - const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, canvasSize.vertical], { - stroke: 'black', - strokeWidth: 1, - selectable: false, - name: 'mouseLine', - }) - - // 선들을 캔버스에 추가합니다. - canvas?.add(horizontalLine, verticalLine) - - // 캔버스를 다시 그립니다. - canvas?.renderAll() - } - - //가로, 세로 선 삭제 - const removeMouseLines = () => { - if (canvas?._objects.length > 0) { - const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine') - mouseLines.forEach((item) => canvas?.remove(item)) - } - canvas?.renderAll() - } - /** * 각종 키보드 이벤트 * https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values @@ -216,6 +181,16 @@ export function useCanvasEvent() { case 'Esc': // IE/Edge에서 사용되는 값 case 'Escape': break + + case 'z': + if (!e.ctrlKey) { + return + } + + console.log('뒤로가기') + + break + default: return // 키 이벤트를 처리하지 않는다면 종료합니다. } @@ -235,6 +210,7 @@ export function useCanvasEvent() { } targetObj.set({ top: top }) + targetObj.fire('modified') canvas?.renderAll() } @@ -251,6 +227,7 @@ export function useCanvasEvent() { } targetObj.set({ top: top }) + targetObj.fire('modified') canvas?.renderAll() } @@ -267,6 +244,7 @@ export function useCanvasEvent() { } targetObj.set({ left: left }) + targetObj.fire('modified') canvas?.renderAll() } @@ -283,9 +261,29 @@ export function useCanvasEvent() { } targetObj.set({ left: left }) + targetObj.fire('modified') canvas?.renderAll() } + /** + * 선택한 도형을 삭제한다. + */ + const handleDelete = () => { + const targets = canvas?.getActiveObjects() + if (targets?.length === 0) { + alert('삭제할 대상을 선택해주세요.') + return + } + + if (!confirm('정말로 삭제하시겠습니까?')) { + return + } + + targets?.forEach((target) => { + canvas?.remove(target) + }) + } + return { setCanvasForEvent, attachDefaultEventOnCanvas,