Merge branch 'dev' of https://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into dev-ck
This commit is contained in:
commit
00b8c8bf5b
@ -31,6 +31,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@turf/turf": "^7.0.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.3.3",
|
||||
"prisma": "^5.18.0",
|
||||
|
||||
@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react'
|
||||
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { modalContent, modalState } from '@/store/modalAtom'
|
||||
import { guideLineState } from '@/store/canvasAtom'
|
||||
import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
|
||||
export default function SettingsModal(props) {
|
||||
@ -16,6 +16,8 @@ export default function SettingsModal(props) {
|
||||
|
||||
const [open, setOpen] = useRecoilState(modalState)
|
||||
const [guideLine, setGuideLine] = useRecoilState(guideLineState)
|
||||
const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
|
||||
const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
|
||||
|
||||
const gridSettingArray = []
|
||||
|
||||
@ -63,6 +65,7 @@ export default function SettingsModal(props) {
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
name: 'guideLine',
|
||||
direction: 'horizontal',
|
||||
},
|
||||
)
|
||||
canvasProps.add(horizontalLine)
|
||||
@ -82,6 +85,7 @@ export default function SettingsModal(props) {
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
name: 'guideLine',
|
||||
direction: 'vertical',
|
||||
},
|
||||
)
|
||||
canvasProps.add(verticalLine)
|
||||
@ -99,6 +103,16 @@ export default function SettingsModal(props) {
|
||||
moduleHoriLength: moduleHoriLength,
|
||||
}
|
||||
gridSettingArray.push(recoilObj)
|
||||
const newHoriGuideLines = [...horiGuideLines]
|
||||
horizontalLineArray.forEach((line) => {
|
||||
newHoriGuideLines.push(line)
|
||||
})
|
||||
const newVertGuideLines = [...vertGuideLines]
|
||||
verticalLineArray.forEach((line) => {
|
||||
newVertGuideLines.push(line)
|
||||
})
|
||||
setHoriGuideLines(newHoriGuideLines)
|
||||
setVertGuideLines(newVertGuideLines)
|
||||
}
|
||||
|
||||
if (gridCheckedValue.includes('dot')) {
|
||||
@ -170,6 +184,8 @@ export default function SettingsModal(props) {
|
||||
guideLines?.forEach((item) => canvasProps.remove(item))
|
||||
canvasProps.renderAll()
|
||||
setGuideLine([])
|
||||
setHoriGuideLines([])
|
||||
setVertGuideLines([])
|
||||
} else {
|
||||
alert('그리드가 없습니다.')
|
||||
return
|
||||
|
||||
@ -425,6 +425,8 @@ export function useCanvas(id) {
|
||||
'maxY',
|
||||
'minX',
|
||||
'minY',
|
||||
'x',
|
||||
'y',
|
||||
])
|
||||
|
||||
const str = JSON.stringify(objs)
|
||||
|
||||
@ -19,9 +19,9 @@ export function useCanvasEvent() {
|
||||
canvas?.on('selection:cleared', selectionEvent.cleared)
|
||||
canvas?.on('selection:created', selectionEvent.created)
|
||||
canvas?.on('selection:updated', selectionEvent.updated)
|
||||
canvas?.on('object:added', () => {
|
||||
/*canvas?.on('object:added', () => {
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
})
|
||||
})*/
|
||||
canvas?.on('object:removed', objectEvent.removed)
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import {
|
||||
calculateIntersection,
|
||||
distanceBetweenPoints,
|
||||
@ -25,6 +25,8 @@ import {
|
||||
templateTypeState,
|
||||
wallState,
|
||||
guideLineState,
|
||||
horiGuideLinesState,
|
||||
vertGuideLinesState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
import { fabric } from 'fabric'
|
||||
@ -64,23 +66,22 @@ export function useMode() {
|
||||
const compass = useRecoilValue(compassState)
|
||||
const [isCellCenter, setIsCellCenter] = useState(false)
|
||||
|
||||
const guideLineInfo = useRecoilValue(guideLineState)
|
||||
const [guideLineInfo, setGuideLineInfo] = useRecoilState(guideLineState)
|
||||
|
||||
const [guideLineMode, setGuideLineMode] = useState(false)
|
||||
const [guideDotMode, setGuideDotMode] = useState(false)
|
||||
|
||||
const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
|
||||
const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
|
||||
|
||||
useEffect(() => {
|
||||
// 이벤트 리스너 추가
|
||||
// if (!canvas) {
|
||||
// canvas?.setZoom(0.8)
|
||||
// return
|
||||
// }
|
||||
document.addEventListener('keydown', handleKeyDown)
|
||||
if (!canvas) return
|
||||
setCanvas(canvas)
|
||||
canvas?.on('mouse:move', drawMouseLines)
|
||||
// 컴포넌트가 언마운트될 때 이벤트 리스너 제거
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
}
|
||||
}, [canvas]) // 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행되도록 함
|
||||
|
||||
useEffect(() => {
|
||||
@ -100,15 +101,10 @@ export function useMode() {
|
||||
}, [endPoint])
|
||||
|
||||
useEffect(() => {
|
||||
changeMode(canvas, mode)
|
||||
canvas?.off('mouse:move')
|
||||
canvas?.on('mouse:move', drawMouseLines)
|
||||
changeMode(canvas, mode)
|
||||
/*
|
||||
if (mode === Mode.EDIT) {
|
||||
canvas?.off('mouse:down')
|
||||
canvas?.on('mouse:down', mouseEvent.editMode)
|
||||
}*/
|
||||
}, [mode])
|
||||
}, [mode, horiGuideLines, vertGuideLines])
|
||||
|
||||
useEffect(() => {
|
||||
setGuideLineMode(false)
|
||||
@ -142,8 +138,8 @@ export function useMode() {
|
||||
}
|
||||
|
||||
if (isGuideLineMode) {
|
||||
horizontalLineArray = [...guideLineState[0].horizontalLineArray]
|
||||
verticalLineArray = [...guideLineState[0].verticalLineArray]
|
||||
horizontalLineArray = [...horiGuideLines]
|
||||
verticalLineArray = [...vertGuideLines]
|
||||
guideLineLengthHori = Number(guideLineState[0].moduleHoriLength)
|
||||
guideLineLengthVert = Number(guideLineState[0].moduleVertLength)
|
||||
}
|
||||
@ -163,13 +159,8 @@ export function useMode() {
|
||||
|
||||
if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) {
|
||||
let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null
|
||||
|
||||
if (isGuideLineMode && isGuideDotMode) {
|
||||
const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray)
|
||||
const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray)
|
||||
const xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
|
||||
const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
|
||||
|
||||
if ((horiGuideLines.length > 0 || vertGuideLines.length > 0) && guideDotMode) {
|
||||
} else if (guideDotMode) {
|
||||
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
|
||||
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
|
||||
|
||||
@ -181,35 +172,28 @@ export function useMode() {
|
||||
if (isAttachX && isAttachY) {
|
||||
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2
|
||||
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2
|
||||
} else {
|
||||
if (Math.min(xDiff, yDiff) <= 20) {
|
||||
if (xDiff < yDiff) {
|
||||
newX = closetVerticalLine.x1
|
||||
newY = pointer.y
|
||||
} else {
|
||||
newX = pointer.x
|
||||
newY = closestHorizontalLine.y1
|
||||
}
|
||||
}
|
||||
} else if (horiGuideLines.length > 0 || vertGuideLines.length > 0) {
|
||||
const closestHorizontalLine = getClosestHorizontalLine(pointer, horiGuideLines)
|
||||
const closetVerticalLine = getClosestVerticalLine(pointer, vertGuideLines)
|
||||
let intersection = null
|
||||
let intersectionDistance = Infinity
|
||||
|
||||
if (closestHorizontalLine && closetVerticalLine) {
|
||||
intersection = calculateIntersection(closestHorizontalLine, closetVerticalLine)
|
||||
if (intersection) {
|
||||
intersectionDistance = distanceBetweenPoints(pointer, intersection)
|
||||
}
|
||||
}
|
||||
} else if (isGuideDotMode) {
|
||||
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
|
||||
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
|
||||
|
||||
const xRate = x / guideLineLengthHori
|
||||
const yRate = y / guideLineLengthVert
|
||||
const isAttachX = xRate >= 0.4 && xRate <= 0.7
|
||||
const isAttachY = yRate >= 0.4 && yRate <= 0.7
|
||||
let xDiff, yDiff
|
||||
|
||||
if (isAttachX && isAttachY) {
|
||||
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2
|
||||
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2
|
||||
if (closetVerticalLine) {
|
||||
xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
|
||||
}
|
||||
if (closestHorizontalLine) {
|
||||
yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
|
||||
}
|
||||
} else if (isGuideLineMode) {
|
||||
const closestHorizontalLine = getClosestHorizontalLine(pointer, horizontalLineArray)
|
||||
const closetVerticalLine = getClosestVerticalLine(pointer, verticalLineArray)
|
||||
const xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
|
||||
const yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
|
||||
|
||||
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
|
||||
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
|
||||
@ -218,23 +202,26 @@ export function useMode() {
|
||||
const yRate = y / guideLineLengthVert
|
||||
const isAttachX = xRate >= 0.4 && xRate <= 0.7
|
||||
const isAttachY = yRate >= 0.4 && yRate <= 0.7
|
||||
|
||||
if (isAttachX && isAttachY) {
|
||||
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2
|
||||
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2
|
||||
} else {
|
||||
if (Math.min(xDiff, yDiff) <= 20) {
|
||||
if (xDiff < yDiff) {
|
||||
newX = closetVerticalLine.x1
|
||||
newY = pointer.y
|
||||
} else {
|
||||
newX = pointer.x
|
||||
newY = closestHorizontalLine.y1
|
||||
if (intersection && intersectionDistance < 20) {
|
||||
newX = intersection.x
|
||||
newY = intersection.y
|
||||
} else {
|
||||
if (Math.min(xDiff, yDiff) <= 20) {
|
||||
if (xDiff < yDiff) {
|
||||
newX = closetVerticalLine.x1
|
||||
newY = pointer.y
|
||||
} else {
|
||||
newX = pointer.x
|
||||
newY = closestHorizontalLine.y1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) < 20) {
|
||||
newX = adsorptionPoint.left
|
||||
newY = adsorptionPoint.top
|
||||
@ -362,16 +349,13 @@ export function useMode() {
|
||||
|
||||
// 모드에 따른 마우스 이벤트 변경
|
||||
const changeMouseEvent = (mode) => {
|
||||
canvas?.off('mouse:down')
|
||||
switch (mode) {
|
||||
case 'drawLine':
|
||||
canvas?.on('mouse:down', mouseEvent.drawLineModeLeftClick)
|
||||
window.document.removeEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
|
||||
window.document.addEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
|
||||
document.addEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
|
||||
break
|
||||
case 'edit':
|
||||
canvas?.on('mouse:down', mouseEvent.editMode)
|
||||
|
||||
break
|
||||
case 'textbox':
|
||||
canvas?.on('mouse:down', mouseEvent.textboxMode)
|
||||
@ -394,9 +378,6 @@ export function useMode() {
|
||||
}
|
||||
}
|
||||
|
||||
// 모드에 따른 키보드 이벤트 변경
|
||||
const changeKeyboardEvent = (mode) => {}
|
||||
|
||||
const keyValid = () => {
|
||||
if (points.current.length === 0) {
|
||||
alert('시작점을 선택해주세요')
|
||||
@ -552,77 +533,98 @@ export function useMode() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleKeyDown = (e) => {
|
||||
switch (e.key) {
|
||||
case 'ArrowDown': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
const verticalLength = Number(prompt('길이를 입력하세요:'))
|
||||
const horizontalLength = 0
|
||||
const mouseAndkeyboardEventClear = () => {
|
||||
canvas?.off('mouse:down')
|
||||
Object.keys(mouseEvent).forEach((key) => {
|
||||
canvas?.off('mouse:down', mouseEvent[key])
|
||||
document.removeEventListener('contextmenu', mouseEvent[key])
|
||||
})
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
Object.keys(keyboardEvent).forEach((key) => {
|
||||
document.removeEventListener('keydown', keyboardEvent[key])
|
||||
})
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
case 'ArrowUp': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
const verticalLength = -Number(prompt('길이를 입력하세요:'))
|
||||
const horizontalLength = 0
|
||||
const keyboardEvent = {
|
||||
// rerendering을 막기 위해 useCallback 사용
|
||||
editMode: useCallback(
|
||||
(e) => {
|
||||
e.preventDefault()
|
||||
switch (e.key) {
|
||||
case 'ArrowDown': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
const verticalLength = Number(prompt('길이를 입력하세요:'))
|
||||
const horizontalLength = 0
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
|
||||
break
|
||||
}
|
||||
case 'ArrowLeft': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
const verticalLength = 0
|
||||
const horizontalLength = -Number(prompt('길이를 입력하세요:'))
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
|
||||
break
|
||||
}
|
||||
case 'ArrowRight': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
|
||||
const verticalLength = 0
|
||||
const horizontalLength = Number(prompt('길이를 입력하세요:'))
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'Enter': {
|
||||
const result = prompt('입력하세요 (a(A패턴),b(B패턴),t(지붕))')
|
||||
|
||||
switch (result) {
|
||||
case 'a':
|
||||
applyTemplateA()
|
||||
break
|
||||
case 'b':
|
||||
applyTemplateB()
|
||||
}
|
||||
case 'ArrowUp': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
const verticalLength = -Number(prompt('길이를 입력하세요:'))
|
||||
const horizontalLength = 0
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
|
||||
break
|
||||
case 't':
|
||||
templateMode()
|
||||
}
|
||||
case 'ArrowLeft': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
const verticalLength = 0
|
||||
const horizontalLength = -Number(prompt('길이를 입력하세요:'))
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
|
||||
break
|
||||
}
|
||||
case 'ArrowRight': {
|
||||
if (!keyValid()) {
|
||||
return
|
||||
}
|
||||
|
||||
const verticalLength = 0
|
||||
const horizontalLength = Number(prompt('길이를 입력하세요:'))
|
||||
|
||||
drawCircleAndLine(verticalLength, horizontalLength)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
case 'Enter': {
|
||||
const result = prompt('입력하세요 (a(A패턴),b(B패턴),t(지붕))')
|
||||
|
||||
switch (result) {
|
||||
case 'a':
|
||||
applyTemplateA()
|
||||
break
|
||||
case 'b':
|
||||
applyTemplateB()
|
||||
break
|
||||
case 't':
|
||||
templateMode()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[canvas],
|
||||
),
|
||||
}
|
||||
|
||||
const changeMode = (canvas, mode) => {
|
||||
mouseAndkeyboardEventClear()
|
||||
setMode(mode)
|
||||
setCanvas(canvas)
|
||||
|
||||
// mode별 이벤트 변경
|
||||
|
||||
changeMouseEvent(mode)
|
||||
changeKeyboardEvent(mode)
|
||||
|
||||
@ -657,40 +659,82 @@ export function useMode() {
|
||||
}
|
||||
}
|
||||
|
||||
const changeKeyboardEvent = (mode) => {
|
||||
if (mode === Mode.EDIT) {
|
||||
switch (mode) {
|
||||
case 'edit':
|
||||
document.addEventListener('keydown', keyboardEvent.editMode)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const mouseEvent = {
|
||||
drawLineModeLeftClick: (options) => {
|
||||
if (mode !== Mode.DRAW_LINE) {
|
||||
return
|
||||
}
|
||||
const pointer = canvas?.getPointer(options.e)
|
||||
|
||||
const line = new QLine(
|
||||
[pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다.
|
||||
[pointer.x, 0, pointer.x, canvasSize.vertical], // y축에 1자 선을 그립니다.
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 2,
|
||||
viewLengthText: true,
|
||||
selectable: false,
|
||||
fontSize: fontSize,
|
||||
stroke: 'gray',
|
||||
strokeWidth: 1,
|
||||
selectable: true,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
lockRotation: true,
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
name: 'guideLine',
|
||||
direction: 'vertical',
|
||||
},
|
||||
)
|
||||
|
||||
canvas?.add(line)
|
||||
canvas?.renderAll()
|
||||
},
|
||||
drawLineModeRightClick: (options) => {
|
||||
const line = new fabric.Line(
|
||||
[0, options.offsetY, canvas.width, options.offsetY], // y축에 1자 선을 그립니다.
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 2,
|
||||
viewLengthText: true,
|
||||
selectable: false,
|
||||
fontSize: fontSize,
|
||||
},
|
||||
)
|
||||
|
||||
canvas?.add(line)
|
||||
canvas?.renderAll()
|
||||
const newVerticalLineArray = [...vertGuideLines]
|
||||
newVerticalLineArray.push(line)
|
||||
|
||||
setVertGuideLines(newVerticalLineArray)
|
||||
},
|
||||
drawLineModeRightClick: useCallback(
|
||||
(options) => {
|
||||
document.removeEventListener('contextmenu', mouseEvent.drawLineModeRightClick)
|
||||
if (mode !== Mode.DRAW_LINE) {
|
||||
return
|
||||
}
|
||||
const line = new fabric.Line(
|
||||
[0, options.offsetY, canvasSize.horizontal, options.offsetY], // y축에 1자 선을 그립니다.
|
||||
{
|
||||
stroke: 'gray',
|
||||
strokeWidth: 1,
|
||||
selectable: true,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
lockRotation: true,
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
name: 'guideLine',
|
||||
direction: 'horizontal',
|
||||
},
|
||||
)
|
||||
|
||||
canvas?.add(line)
|
||||
canvas?.renderAll()
|
||||
|
||||
const newHorizontalLineArray = [...horiGuideLines]
|
||||
newHorizontalLineArray.push(line)
|
||||
setHoriGuideLines(newHorizontalLineArray)
|
||||
},
|
||||
[canvas, mode, horiGuideLines],
|
||||
),
|
||||
editMode: (options) => {
|
||||
if (mode !== Mode.EDIT) {
|
||||
return
|
||||
}
|
||||
let pointer = canvas?.getPointer(options.e)
|
||||
|
||||
if (getInterSectPointByMouseLine()) {
|
||||
@ -801,7 +845,9 @@ export function useMode() {
|
||||
|
||||
canvas?.renderAll()
|
||||
},
|
||||
|
||||
textboxMode: (options) => {
|
||||
if (mode !== Mode.TEXTBOX) return
|
||||
if (canvas?.getActiveObject()?.type === 'textbox') return
|
||||
const pointer = canvas?.getPointer(options.e)
|
||||
|
||||
@ -821,6 +867,7 @@ export function useMode() {
|
||||
})
|
||||
},
|
||||
drawRectMode: (o) => {
|
||||
if (mode !== Mode.DRAW_RECT) return
|
||||
let rect, isDown, origX, origY
|
||||
isDown = true
|
||||
const pointer = canvas.getPointer(o.e)
|
||||
@ -862,7 +909,8 @@ export function useMode() {
|
||||
})
|
||||
},
|
||||
// 흡착점 추가
|
||||
adsorptionPoint(o) {
|
||||
adsorptionPoint: (o) => {
|
||||
if (mode !== Mode.ADSORPTION_POINT) return
|
||||
const pointer = canvas.getPointer(o.e)
|
||||
let newX = pointer.x
|
||||
let newY = pointer.y
|
||||
@ -4484,7 +4532,6 @@ export function useMode() {
|
||||
|
||||
canvas?.off('mouse:move')
|
||||
canvas?.off('mouse:out')
|
||||
document.removeEventListener('keydown', handleKeyDown)
|
||||
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
||||
roofs.forEach((roof, index) => {
|
||||
const offsetPolygonPoint = offsetPolygon(roof.points, -20)
|
||||
|
||||
@ -95,3 +95,15 @@ export const currentObjectState = atom({
|
||||
default: null,
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
export const horiGuideLinesState = atom({
|
||||
key: 'horiGuideLines',
|
||||
default: [],
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
export const vertGuideLinesState = atom({
|
||||
key: 'vertGuideLines',
|
||||
default: [],
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
@ -9,3 +9,45 @@ export const isObjectNotEmpty = (obj) => {
|
||||
}
|
||||
return Object.keys(obj).length > 0
|
||||
}
|
||||
|
||||
/**
|
||||
* ex) const params = {page:10, searchDvsnCd: 20}
|
||||
* @param {*} params
|
||||
* @returns page=10&searchDvsnCd=20
|
||||
*/
|
||||
export const queryStringFormatter = (params = {}) => {
|
||||
const queries = []
|
||||
Object.keys(params).forEach((parameterKey) => {
|
||||
const parameterValue = params[parameterKey]
|
||||
|
||||
if (parameterValue === undefined || parameterValue === null) {
|
||||
return
|
||||
}
|
||||
|
||||
// string trim
|
||||
if (typeof parameterValue === 'string' && !parameterValue.trim()) {
|
||||
return
|
||||
}
|
||||
|
||||
// array to query string
|
||||
if (Array.isArray(parameterValue)) {
|
||||
// primitive type
|
||||
if (parameterValue.every((v) => typeof v === 'number' || typeof v === 'string')) {
|
||||
queries.push(`${encodeURIComponent(parameterKey)}=${parameterValue.map((v) => encodeURIComponent(v)).join(',')}`)
|
||||
return
|
||||
}
|
||||
// reference type
|
||||
if (parameterValue.every((v) => typeof v === 'object' && v !== null)) {
|
||||
parameterValue.map((pv, i) => {
|
||||
return Object.keys(pv).forEach((valueKey) => {
|
||||
queries.push(`${encodeURIComponent(`${parameterKey}[${i}].${valueKey}`)}=${encodeURIComponent(pv[valueKey])}`)
|
||||
})
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
// 나머지
|
||||
queries.push(`${encodeURIComponent(parameterKey)}=${encodeURIComponent(parameterValue)}`)
|
||||
})
|
||||
return queries.join('&')
|
||||
}
|
||||
|
||||
@ -4319,6 +4319,11 @@ date-fns@^3.3.1:
|
||||
resolved "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz"
|
||||
integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==
|
||||
|
||||
dayjs@^1.11.13:
|
||||
version "1.11.13"
|
||||
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.13.tgz#92430b0139055c3ebb60150aa13e860a4b5a366c"
|
||||
integrity sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==
|
||||
|
||||
debug@4, debug@^4.3.3, debug@^4.3.4:
|
||||
version "4.3.5"
|
||||
resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user