event 분리

This commit is contained in:
hyojun.choi 2024-08-22 14:53:10 +09:00
parent 363f3a1d01
commit 20caabf732
8 changed files with 441 additions and 350 deletions

20
src/common/common.js Normal file
View File

@ -0,0 +1,20 @@
export const Mode = {
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
EDIT: 'edit',
TEMPLATE: 'template',
PATTERNA: 'patterna',
PATTERNB: 'patternb',
TEXTBOX: 'textbox',
DRAW_RECT: 'drawRect',
ROOF_PATTERN: 'roofPattern', //지붕패턴 모드
ROOF_TRESTLE: 'roofTrestle', //지붕가대 모드
FILL_CELLS: 'fillCells', //태양광셀 모드
CELL_POWERCON: 'cellPowercon', //파워콘
DRAW_HELP_LINE: 'drawHelpLine', // 보조선 그리기 모드 지붕 존재해야함
DEFAULT: 'default',
}
export const LineType = {
EAVES: 'eaves', // 처마
RIDGE: 'ridge', // 용마루....
}

View File

@ -2,7 +2,7 @@
import { useCanvas } from '@/hooks/useCanvas'
import { useEffect, useState, useRef } from 'react'
import { Mode, useMode } from '@/hooks/useMode'
import { useMode } from '@/hooks/useMode'
import { Button } from '@nextui-org/react'
import RangeSlider from './ui/RangeSlider'
import { useRecoilState, useRecoilValue } from 'recoil'
@ -22,6 +22,7 @@ import { calculateIntersection } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon'
import ThumbnailList from './ui/ThumbnailLIst'
import CanvasWithContextMenu from '@/util/context-util'
import { Mode } from '@/common/common'
export default function Roof2() {
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')

View File

@ -104,6 +104,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
const maxX = this.left + this.width
const minY = this.top
const maxY = this.top + this.length
const degree = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI
const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
left: left,
@ -114,6 +115,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
minY,
maxY,
parentDirection: this.direction,
parentDegree: degree,
parentId: this.id,
editable: false,
selectable: true,

View File

@ -173,6 +173,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2)
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
// Create new text object if it doesn't exist
const text = new fabric.Text(length.toFixed(0), {
left: midPoint.x,
@ -184,6 +186,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
minY: Math.min(start.y, end.y),
maxY: Math.max(start.y, end.y),
parentDirection: getDirectionByPoint(start, end),
parentDegree: degree,
dirty: true,
editable: false,
selectable: true,

View File

@ -10,6 +10,7 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import { defineQLine } from '@/util/qline-utils'
import { defineQPloygon } from '@/util/qpolygon-utils'
import { writeImage } from '@/lib/canvas'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
export function useCanvas(id) {
const [canvas, setCanvas] = useState()
@ -17,7 +18,7 @@ export function useCanvas(id) {
const [history, setHistory] = useState([])
const [canvasSize] = useRecoilState(canvasSizeState)
const [fontSize] = useRecoilState(fontSizeState)
const points = useRef([])
const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent()
/**
* 처음 셋팅
@ -31,6 +32,8 @@ export function useCanvas(id) {
})
setCanvas(c)
setCanvasForEvent(c)
return () => {
c.dispose()
}
@ -38,8 +41,7 @@ export function useCanvas(id) {
useEffect(() => {
// canvas 사이즈가 변경되면 다시
removeEventOnCanvas()
addEventOnCanvas()
attachDefaultEventOnCanvas()
}, [canvasSize])
useEffect(() => {
@ -65,113 +67,10 @@ export function useCanvas(id) {
useEffect(() => {
if (canvas) {
initialize()
removeEventOnCanvas()
addEventOnCanvas()
attachDefaultEventOnCanvas()
}
}, [canvas])
const addEventOnCanvas = () => {
canvas?.on('object:added', onChange)
canvas?.on('object:added', addEventOnObject)
canvas?.on('object:modified', onChange)
canvas?.on('object:removed', onChange)
canvas?.on('object:added', () => {
document.addEventListener('keydown', handleKeyDown)
})
canvas?.on('mouse:move', drawMouseLines)
canvas?.on('mouse:down', handleMouseDown)
canvas?.on('mouse:out', removeMouseLines)
}
const removeEventOnCanvas = () => {
canvas?.off('object:added')
canvas?.off('object:modified')
canvas?.off('object:removed')
canvas?.off('object:added')
canvas?.off('mouse:move')
canvas?.off('mouse:down')
}
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()
})
}
}
/**
* 마우스 포인터의 가이드라인을 제거합니다.
*/
@ -220,71 +119,6 @@ export function useCanvas(id) {
setIsLocked(false)
}
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 handleMouseDown = (e) => {
// 현재 마우스 포인터의 위치를 가져옵니다.
if (canvas?.getActiveObject()) {
points.current = []
return
}
const pointer = canvas?.getPointer(e.e)
// 클릭한 위치를 배열에 추가합니다.
points.current.push(pointer)
// 두 점을 모두 찍었을 때 사각형을 그립니다.
if (points.current.length === 2) {
const rect = new fabric.Rect({
left: points.current[0].x,
top: points.current[0].y,
width: points.current[1].x - points.current[0].x,
height: points.current[1].y - points.current[0].y,
fill: 'transparent',
stroke: 'black',
strokeWidth: 1,
})
// 사각형을 캔버스에 추가합니다.
canvas?.add(rect)
// 배열을 초기화합니다.
points.current = []
}
}
/**
* 눈금 모양에 맞게 움직이도록 한다.
*/
@ -459,50 +293,6 @@ export function useCanvas(id) {
canvas?.renderAll()
}
/**
* 각종 키보드 이벤트
* https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values
*/
const handleKeyDown = (e) => {
const key = e.key
switch (key) {
case 'Delete':
case 'Backspace':
handleDelete()
break
case 'Down': // IE/Edge에서 사용되는 값
case 'ArrowDown':
// "아래 화살표" 키가 눌렸을 때의 동작입니다.
moveDown()
break
case 'Up': // IE/Edge에서 사용되는 값
case 'ArrowUp':
// "위 화살표" 키가 눌렸을 때의 동작입니다.
moveUp()
break
case 'Left': // IE/Edge에서 사용되는 값
case 'ArrowLeft':
// "왼쪽 화살표" 키가 눌렸을 때의 동작입니다.
moveLeft()
break
case 'Right': // IE/Edge에서 사용되는 값
case 'ArrowRight':
// "오른쪽 화살표" 키가 눌렸을 때의 동작입니다.
moveRight()
break
case 'Enter':
// "enter" 또는 "return" 키가 눌렸을 때의 동작입니다.
break
case 'Esc': // IE/Edge에서 사용되는 값
case 'Escape':
break
default:
return // 키 이벤트를 처리하지 않는다면 종료합니다.
}
e.preventDefault()
}
const handleRotate = (degree = 45) => {
const target = canvas?.getActiveObject()

277
src/hooks/useCanvasEvent.js Normal file
View File

@ -0,0 +1,277 @@
import { useEffect, useState } from 'react'
import { fabric } from 'fabric'
import { useRecoilValue } from 'recoil'
import { canvasSizeState, modeState } from '@/store/canvasAtom'
// 캔버스에 필요한 이벤트
export function useCanvasEvent() {
const [canvas, setCanvasForEvent] = useState(null)
const canvasSize = useRecoilValue(canvasSizeState)
// 기본적인 이벤트 필요시 추가
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', () => {
document.addEventListener('keydown', handleKeyDown)
})
canvas?.on('mouse:move', drawMouseLines)
canvas?.on('mouse:out', removeMouseLines)
}
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('mouse:move')
canvas?.off('mouse:down')
}
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
*/
const handleKeyDown = (e) => {
const key = e.key
switch (key) {
case 'Delete':
case 'Backspace':
handleDelete()
break
case 'Down': // IE/Edge에서 사용되는 값
case 'ArrowDown':
// "아래 화살표" 키가 눌렸을 때의 동작입니다.
moveDown()
break
case 'Up': // IE/Edge에서 사용되는 값
case 'ArrowUp':
// "위 화살표" 키가 눌렸을 때의 동작입니다.
moveUp()
break
case 'Left': // IE/Edge에서 사용되는 값
case 'ArrowLeft':
// "왼쪽 화살표" 키가 눌렸을 때의 동작입니다.
moveLeft()
break
case 'Right': // IE/Edge에서 사용되는 값
case 'ArrowRight':
// "오른쪽 화살표" 키가 눌렸을 때의 동작입니다.
moveRight()
break
case 'Enter':
// "enter" 또는 "return" 키가 눌렸을 때의 동작입니다.
break
case 'Esc': // IE/Edge에서 사용되는 값
case 'Escape':
break
default:
return // 키 이벤트를 처리하지 않는다면 종료합니다.
}
e.preventDefault()
}
const moveDown = () => {
const targetObj = canvas?.getActiveObject()
if (!targetObj) {
return
}
let top = targetObj.top + 10
if (top > canvasSize.vertical) {
top = canvasSize.vertical
}
targetObj.set({ top: top })
canvas?.renderAll()
}
const moveUp = () => {
const targetObj = canvas?.getActiveObject()
if (!targetObj) {
return
}
let top = targetObj.top - 10
if (top < 0) {
top = 0
}
targetObj.set({ top: top })
canvas?.renderAll()
}
const moveLeft = () => {
const targetObj = canvas?.getActiveObject()
if (!targetObj) {
return
}
let left = targetObj.left - 10
if (left < 0) {
left = 0
}
targetObj.set({ left: left })
canvas?.renderAll()
}
const moveRight = () => {
const targetObj = canvas?.getActiveObject()
if (!targetObj) {
return
}
let left = targetObj.left + 10
if (left > canvasSize.horizontal) {
left = canvasSize.horizontal
}
targetObj.set({ left: left })
canvas?.renderAll()
}
return {
setCanvasForEvent,
attachDefaultEventOnCanvas,
}
}

View File

@ -23,6 +23,7 @@ import {
templateTypeState,
wallState,
compassState,
modeState,
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { fabric } from 'fabric'
@ -30,25 +31,10 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import offsetPolygon from '@/util/qpolygon-utils'
import { isObjectNotEmpty } from '@/util/common-utils'
import * as turf from '@turf/turf'
export const Mode = {
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
EDIT: 'edit',
TEMPLATE: 'template',
PATTERNA: 'patterna',
PATTERNB: 'patternb',
TEXTBOX: 'textbox',
DRAW_RECT: 'drawRect',
ROOF_PATTERN: 'roofPattern', //지붕패턴 모드
ROOF_TRESTLE: 'roofTrestle', //지붕가대 모드
FILL_CELLS: 'fillCells', //태양광셀 모드
CELL_POWERCON: 'cellPowercon', //파워콘
DRAW_HELP_LINE: 'drawHelpLine', // 보조선 그리기 모드 지붕 존재해야함
DEFAULT: 'default',
}
import { Mode } from '@/common/common'
export function useMode() {
const [mode, setMode] = useState()
const [mode, setMode] = useRecoilState(modeState)
const points = useRef([])
const historyPoints = useRef([])
const historyLines = useRef([])
@ -233,49 +219,28 @@ export function useMode() {
canvas?.renderAll()
}
const addEvent = (mode) => {
// 각 모드에 따른 마우스 이벤트 변경
const changeMouseEvent = (mode) => {
canvas?.off('mouse:down')
switch (mode) {
case 'drawLine':
drawLineMode()
canvas?.on('mouse:down', mouseEvent.drawLineMode)
break
case 'edit':
editMode()
break
case 'template':
templateMode()
break
case 'patterna':
applyTemplateA()
break
case 'patternb':
applyTemplateB()
canvas?.on('mouse:down', mouseEvent.editMode)
break
case 'textbox':
textboxMode()
canvas?.on('mouse:down', mouseEvent.textboxMode)
break
case 'drawRect':
drawRectMode()
break
case 'roofPattern':
makeRoofPatternPolygon()
break
case 'roofTrestle':
makeRoofTrestle()
break
case 'fillCells':
makeRoofFillCells()
break
case 'cellPowercon':
makeCellPowercon()
canvas?.on('mouse:down', mouseEvent.drawRectMode)
break
case 'drawHelpLine':
canvas?.off('selection:created', addSelectCreatedEvent)
canvas?.off('selection:cleared', addSelectClearedEvent)
canvas?.on('selection:created', addSelectCreatedEvent)
canvas?.on('selection:cleared', addSelectClearedEvent)
drawHelpLineMode()
break
case 'default':
canvas?.off('mouse:down')
break
@ -504,19 +469,62 @@ export function useMode() {
}
const changeMode = (canvas, mode) => {
setEndPoint(null)
pointCount.current = 0
setMode(mode)
// mode변경 시 이전 이벤트 제거
setCanvas(canvas)
canvas?.off('mouse:down')
addEvent(mode)
changeMouseEvent(mode)
switch (mode) {
case 'template':
templateMode()
break
case 'patterna':
applyTemplateA()
break
case 'patternb':
applyTemplateB()
break
case 'roofPattern':
makeRoofPatternPolygon()
break
case 'roofTrestle':
makeRoofTrestle()
break
case 'fillCells':
makeRoofFillCells()
break
case 'cellPowercon':
makeCellPowercon()
break
case 'drawHelpLine':
drawHelpLineMode()
break
case 'default':
clearEditMode()
break
}
}
const editMode = () => {
canvas?.on('mouse:down', function (options) {
const mouseEvent = {
drawLineMode: (options) => {
const pointer = canvas?.getPointer(options.e)
const line = new QLine(
[pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다.
{
stroke: 'black',
strokeWidth: 2,
viewLengthText: true,
selectable: false,
fontSize: fontSize,
},
)
canvas?.add(line)
canvas?.renderAll()
},
editMode: (options) => {
const pointer = canvas?.getPointer(options.e)
const circle = new fabric.Circle({
radius: 5,
@ -585,7 +593,62 @@ export function useMode() {
}
canvas?.renderAll()
})
},
textboxMode: (options) => {
if (canvas?.getActiveObject()?.type === 'textbox') return
const pointer = canvas?.getPointer(options.e)
const textbox = new fabric.Textbox('텍스트를 입력하세요', {
left: pointer.x,
top: pointer.y,
width: 150, // 텍스트박스의 너비를 설정합니다.
fontSize: fontSize, // 텍스트의 크기를 설정합니다.
})
canvas?.add(textbox)
canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다.
canvas?.renderAll()
// textbox가 active가 풀린 경우 editing mode로 변경
textbox?.on('editing:exited', function () {
changeMode(canvas, Mode.EDIT)
})
},
drawRectMode: () => {
let rect, isDown, origX, origY
canvas.on('mouse:down', function (o) {
isDown = true
const pointer = canvas.getPointer(o.e)
origX = pointer.x
origY = pointer.y
rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
angle: 0,
fill: 'transparent',
stroke: 'black',
transparentCorners: false,
})
canvas.add(rect)
})
canvas.on('mouse:move', function (o) {
if (!isDown) return
const pointer = canvas.getPointer(o.e)
if (origX > pointer.x) {
rect.set({ left: Math.abs(pointer.x) })
}
if (origY > pointer.y) {
rect.set({ top: Math.abs(pointer.y) })
}
rect.set({ width: Math.abs(origX - pointer.x) })
rect.set({ height: Math.abs(origY - pointer.y) })
})
},
}
const pushHistoryLine = (line) => {
@ -643,86 +706,6 @@ export function useMode() {
setTemplateType(1)
}
}
const textboxMode = () => {
canvas?.on('mouse:down', function (options) {
if (canvas?.getActiveObject()?.type === 'textbox') return
const pointer = canvas?.getPointer(options.e)
const textbox = new fabric.Textbox('텍스트를 입력하세요', {
left: pointer.x,
top: pointer.y,
width: 150, // 텍스트박스의 너비를 설정합니다.
fontSize: fontSize, // 텍스트의 크기를 설정합니다.
})
canvas?.add(textbox)
canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다.
canvas?.renderAll()
// textbox가 active가 풀린 경우 editing mode로 변경
textbox?.on('editing:exited', function () {
changeMode(canvas, Mode.EDIT)
})
})
}
const drawLineMode = () => {
canvas?.on('mouse:down', function (options) {
const pointer = canvas?.getPointer(options.e)
const line = new QLine(
[pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다.
{
stroke: 'black',
strokeWidth: 2,
viewLengthText: true,
selectable: false,
fontSize: fontSize,
},
)
canvas?.add(line)
canvas?.renderAll()
})
}
const drawRectMode = () => {
let rect, isDown, origX, origY
canvas.on('mouse:down', function (o) {
isDown = true
const pointer = canvas.getPointer(o.e)
origX = pointer.x
origY = pointer.y
rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: pointer.x - origX,
height: pointer.y - origY,
angle: 0,
fill: 'transparent',
stroke: 'black',
transparentCorners: false,
})
canvas.add(rect)
})
canvas.on('mouse:move', function (o) {
if (!isDown) return
const pointer = canvas.getPointer(o.e)
if (origX > pointer.x) {
rect.set({ left: Math.abs(pointer.x) })
}
if (origY > pointer.y) {
rect.set({ top: Math.abs(pointer.y) })
}
rect.set({ width: Math.abs(origX - pointer.x) })
rect.set({ height: Math.abs(origY - pointer.y) })
})
}
/**
* 점을 연결하는 선과 길이를 그립니다.
* a : 시작점, b : 끝점
@ -818,6 +801,7 @@ export function useMode() {
canvas?.clear()
startPoint.current = null
setEndPoint(null)
pointCount.current = 0
setTemplateType(0)
points.current = []
historyPoints.current = []
@ -826,6 +810,15 @@ export function useMode() {
setSelectedCellRoofArray([]) //셀 그린거 삭제
}
const clearEditMode = () => {
startPoint.current = null
setEndPoint(null)
pointCount.current = 0
points.current = []
historyPoints.current = []
historyLines.current = []
}
const zoomIn = () => {
canvas?.setZoom(canvas.getZoom() + 0.1)
setZoom(Math.round(zoom + 10))

View File

@ -5,6 +5,11 @@ export const textState = atom({
default: 'test text',
})
export const modeState = atom({
key: 'modeState',
default: 'default',
})
export const fontSizeState = atom({
key: 'fontSizeState',
default: 16,