Merge branch 'dev' of https://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into dev-ck
This commit is contained in:
commit
64d4b7e472
@ -31,6 +31,28 @@ export default async function RootLayout({ children }) {
|
||||
// const isLoggedIn = await checkSession()
|
||||
const session = await getSession()
|
||||
console.log('session[layout]:', session)
|
||||
|
||||
let sessionProps = {}
|
||||
|
||||
if (session.isLoggedIn) {
|
||||
sessionProps = {
|
||||
userId: session.userId,
|
||||
saleStoreId: session.saleStoreId,
|
||||
name: session.name,
|
||||
mail: session.mail,
|
||||
tel: session.tel,
|
||||
storeId: session.storeId,
|
||||
userNm: session.userNm,
|
||||
userNmKana: session.userNmKana,
|
||||
category: session.category,
|
||||
telNo: session.telNo,
|
||||
fax: session.fax,
|
||||
email: session.email,
|
||||
pwdInitYn: session.pwdInitYn,
|
||||
isLoggedIn: session.isLoggedIn,
|
||||
}
|
||||
}
|
||||
|
||||
if (!headerPathname.includes('/login') && !session.isLoggedIn) {
|
||||
redirect('/login')
|
||||
}
|
||||
@ -41,7 +63,7 @@ export default async function RootLayout({ children }) {
|
||||
<body>
|
||||
{/*{headerPathname !== '/login' && <Headers />}*/}
|
||||
<div className="wrap">
|
||||
<Header loginedUserNm={session?.userNm} />
|
||||
<Header userSession={sessionProps} />
|
||||
<UIProvider>
|
||||
<div className="content">
|
||||
<Dimmed />
|
||||
|
||||
@ -2,21 +2,225 @@ import WithDraggable from '@/components/common/draggable/withDraggable'
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
import { useState } from 'react'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { canvasState, dotLineGridSettingState, dotLineIntervalSelector } from '@/store/canvasAtom'
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||
import { onlyNumberInputChange } from '@/util/input-utils'
|
||||
import { fabric } from 'fabric'
|
||||
|
||||
const TYPE = {
|
||||
DOT: 'DOT',
|
||||
LINE: 'LINE',
|
||||
}
|
||||
|
||||
export default function DotLineGrid(props) {
|
||||
// const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state
|
||||
const [close, setClose] = useState(false)
|
||||
const { setShowDotLineGridModal } = props
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState)
|
||||
const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState)
|
||||
const interval = useRecoilValue(dotLineIntervalSelector)
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const SelectOption = [
|
||||
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin') },
|
||||
{ id: 2, name: '1/2' },
|
||||
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
|
||||
{ id: 2, name: '1/2', value: 1 / 2 },
|
||||
{
|
||||
id: 3,
|
||||
name: '1/4',
|
||||
value: 1 / 4,
|
||||
},
|
||||
{ id: 4, name: '1/10' },
|
||||
{ id: 4, name: '1/10', value: 1 / 10 },
|
||||
]
|
||||
const [selectOption, setSelectOption] = useState(SelectOption[0])
|
||||
|
||||
const HandleClickClose = () => {
|
||||
// setClose(true)
|
||||
// setTimeout(() => {
|
||||
// setModalOption({ ...modalOption, gridoption: false })
|
||||
// setClose(false)
|
||||
// }, 180)
|
||||
}
|
||||
|
||||
const handleCheckBoxChange = (e) => {
|
||||
const { value, checked } = e.target
|
||||
setDotLineGridSettingState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[value]: checked,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const handleSave = () => {
|
||||
// 1. 점.선 그리드 설정으로 만들어진 기존 오브젝트 제거
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'lineGrid')
|
||||
.forEach((obj) => canvas?.remove(obj))
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'dotGrid')
|
||||
.forEach((obj) => canvas?.remove(obj))
|
||||
|
||||
const horizontalInterval = interval.horizontalInterval
|
||||
const verticalInterval = interval.verticalInterval
|
||||
|
||||
if (dotLineGridSetting.DOT) {
|
||||
const circle = new fabric.Circle({
|
||||
radius: 2,
|
||||
fill: 'red',
|
||||
strokeWidth: 0.7,
|
||||
originX: 'center',
|
||||
originY: 'center',
|
||||
selectable: false,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
lockRotation: true,
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
})
|
||||
|
||||
const patternSourceCanvas = new fabric.StaticCanvas(null, {
|
||||
width: horizontalInterval,
|
||||
height: verticalInterval,
|
||||
})
|
||||
|
||||
patternSourceCanvas.add(circle)
|
||||
|
||||
circle.set({
|
||||
left: patternSourceCanvas.width / 2,
|
||||
top: patternSourceCanvas.height / 2,
|
||||
})
|
||||
|
||||
patternSourceCanvas.renderAll()
|
||||
|
||||
const pattern = new fabric.Pattern({
|
||||
source: patternSourceCanvas.getElement(),
|
||||
repeat: 'repeat',
|
||||
})
|
||||
|
||||
const backgroundPolygon = new fabric.Polygon(
|
||||
[
|
||||
{ x: 0, y: 0 },
|
||||
{ x: canvas.width, y: 0 },
|
||||
{ x: canvas.width, y: canvas.height },
|
||||
{ x: 0, y: canvas.height },
|
||||
],
|
||||
{
|
||||
fill: pattern,
|
||||
selectable: false,
|
||||
name: 'dotGrid',
|
||||
},
|
||||
)
|
||||
|
||||
canvas.add(backgroundPolygon)
|
||||
backgroundPolygon.sendToBack()
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
if (dotLineGridSetting.LINE) {
|
||||
for (let i = 0; i < canvas.height / verticalInterval + 1; i++) {
|
||||
const horizontalLine = new fabric.Line(
|
||||
[0, i * verticalInterval - verticalInterval / 2, canvas.width, i * verticalInterval - verticalInterval / 2],
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: true,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
lockRotation: true,
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
name: 'lineGrid',
|
||||
strokeDashArray: [5, 2],
|
||||
opacity: 0.3,
|
||||
direction: 'horizontal',
|
||||
},
|
||||
)
|
||||
canvas.add(horizontalLine)
|
||||
}
|
||||
|
||||
for (let i = 0; i < canvas.width / horizontalInterval + 1; i++) {
|
||||
const verticalLine = new fabric.Line(
|
||||
[i * horizontalInterval - horizontalInterval / 2, 0, i * horizontalInterval - horizontalInterval / 2, canvas.height],
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: true,
|
||||
lockMovementX: true,
|
||||
lockMovementY: true,
|
||||
lockRotation: true,
|
||||
lockScalingX: true,
|
||||
lockScalingY: true,
|
||||
name: 'lineGrid',
|
||||
strokeDashArray: [5, 2],
|
||||
opacity: 0.3,
|
||||
direction: 'vertical',
|
||||
},
|
||||
)
|
||||
canvas.add(verticalLine)
|
||||
}
|
||||
}
|
||||
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
const handleRadioChange = (e) => {
|
||||
const { value, name, checked, selected } = e.target
|
||||
|
||||
setDotLineGridSettingState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
INTERVAL: {
|
||||
...prev.INTERVAL,
|
||||
type: Number(value),
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const changeInput = (value, e) => {
|
||||
const { name } = e.target
|
||||
setDotLineGridSettingState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
INTERVAL: {
|
||||
...prev.INTERVAL,
|
||||
[name]: value,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const changeDimension = (result) => {
|
||||
const { value } = result
|
||||
setDotLineGridSettingState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
INTERVAL: {
|
||||
...prev.INTERVAL,
|
||||
dimension: value,
|
||||
},
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 초기화
|
||||
const reset = () => {
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'lineGrid')
|
||||
.forEach((obj) => canvas?.remove(obj))
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter((obj) => obj.name === 'dotGrid')
|
||||
.forEach((obj) => canvas?.remove(obj))
|
||||
resetDotLineGridSetting()
|
||||
setSelectOption(SelectOption[0])
|
||||
}
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={{ x: -150, y: 300 }}>
|
||||
<div className={`modal-pop-wrap ssm mount`}>
|
||||
@ -29,55 +233,91 @@ export default function DotLineGrid(props) {
|
||||
<div className="modal-body">
|
||||
<div className="grid-check-form">
|
||||
<div className="d-check-box pop">
|
||||
<input type="checkbox" id="ch01" />
|
||||
<input type="checkbox" id="ch01" value={TYPE.DOT} onChange={handleCheckBoxChange} checked={dotLineGridSetting.DOT} />
|
||||
<label htmlFor="ch01">{getMessage('modal.canvas.setting.grid.dot.line.setting.dot.display')}</label>
|
||||
</div>
|
||||
<div className="d-check-box pop">
|
||||
<input type="checkbox" id="ch02" />
|
||||
<input type="checkbox" id="ch02" value={TYPE.LINE} onChange={handleCheckBoxChange} checked={dotLineGridSetting.LINE} />
|
||||
<label htmlFor="ch02">{getMessage('modal.canvas.setting.grid.dot.line.setting.line.display')}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-option-wrap">
|
||||
<div className="grid-option-box">
|
||||
<div className="d-check-radio pop no-text">
|
||||
<input type="radio" name="radio01" id="ra01" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra01"
|
||||
value={1}
|
||||
onChange={handleRadioChange}
|
||||
checked={dotLineGridSetting.INTERVAL.type === 1}
|
||||
/>
|
||||
<label htmlFor="ra01"></label>
|
||||
</div>
|
||||
<div className="grid-input-form">
|
||||
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.horizon')}</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin" defaultValue={910} />
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin"
|
||||
name={`horizontalInterval`}
|
||||
value={dotLineGridSetting.INTERVAL.horizontalInterval}
|
||||
onChange={(e) => onlyNumberInputChange(e, changeInput)}
|
||||
/>
|
||||
</div>
|
||||
<span>mm</span>
|
||||
</div>
|
||||
<div className="grid-input-form">
|
||||
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.vertical')}</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin" defaultValue={910} />
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin"
|
||||
name={`verticalInterval`}
|
||||
value={dotLineGridSetting.INTERVAL.verticalInterval}
|
||||
onChange={(e) => onlyNumberInputChange(e, changeInput)}
|
||||
/>
|
||||
</div>
|
||||
<span>mm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-option-box">
|
||||
<div className="d-check-radio pop no-text">
|
||||
<input type="radio" name="radio01" id="ra02" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra02"
|
||||
value={2}
|
||||
onChange={handleRadioChange}
|
||||
checked={dotLineGridSetting.INTERVAL.type === 2}
|
||||
/>
|
||||
<label htmlFor="ra02"></label>
|
||||
</div>
|
||||
<div className="grid-input-form">
|
||||
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.ratio')}</span>
|
||||
<div className="input-grid mr5">
|
||||
<input type="text" className="input-origin" defaultValue={910} />
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin"
|
||||
name={`ratioInterval`}
|
||||
value={dotLineGridSetting.INTERVAL.ratioInterval}
|
||||
onChange={(e) => onlyNumberInputChange(e, changeInput)}
|
||||
/>
|
||||
</div>
|
||||
<span>mm</span>
|
||||
</div>
|
||||
<div className="grid-select">
|
||||
<QSelectBox title={'原寸'} options={SelectOption} />
|
||||
<QSelectBox options={SelectOption} onChange={changeDimension} value={selectOption} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal mr5">{getMessage('modal.canvas.setting.grid.dot.line.setting.reset')}</button>
|
||||
<button className="btn-frame modal act">{getMessage('modal.canvas.setting.grid.dot.line.setting.save')}</button>
|
||||
<button className="btn-frame modal mr5" onClick={reset}>
|
||||
{getMessage('modal.canvas.setting.grid.dot.line.setting.reset')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={handleSave}>
|
||||
{getMessage('modal.canvas.setting.grid.dot.line.setting.save')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -8,8 +8,10 @@ import { useEvent } from '@/hooks/useEvent'
|
||||
import {
|
||||
adsorptionPointAddModeState,
|
||||
adsorptionPointModeState,
|
||||
adsorptionRangeState,
|
||||
canvasHistoryState,
|
||||
canvasState,
|
||||
dotLineIntervalSelector,
|
||||
verticalHorizontalModeState,
|
||||
} from '@/store/canvasAtom'
|
||||
import {
|
||||
@ -27,22 +29,22 @@ import { distanceBetweenPoints } from '@/util/canvas-util'
|
||||
import { calculateAngle } from '@/util/qpolygon-utils'
|
||||
import { usePolygon } from '@/hooks/usePolygon'
|
||||
import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils'
|
||||
import { useMouse } from '@/hooks/useMouse'
|
||||
|
||||
export default function OuterLineWall(props) {
|
||||
const { setShowOutlineModal } = props
|
||||
const { getMessage } = useMessage()
|
||||
const {
|
||||
addCanvasMouseEventListener,
|
||||
addDocumentEventListener,
|
||||
removeAllMouseEventListeners,
|
||||
removeAllDocumentEventListeners,
|
||||
removeMouseEvent,
|
||||
getIntersectMousePoint,
|
||||
} = useEvent()
|
||||
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } =
|
||||
useEvent()
|
||||
const { getIntersectMousePoint } = useMouse()
|
||||
const { addLine, removeLine } = useLine()
|
||||
|
||||
const { addPolygonByLines } = usePolygon()
|
||||
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
|
||||
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
|
||||
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
||||
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격
|
||||
|
||||
const length1Ref = useRef(null)
|
||||
const length2Ref = useRef(null)
|
||||
@ -72,7 +74,7 @@ export default function OuterLineWall(props) {
|
||||
return () => {
|
||||
removeAllMouseEventListeners()
|
||||
}
|
||||
}, [verticalHorizontalMode, points, adsorptionPointAddMode])
|
||||
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval])
|
||||
|
||||
useEffect(() => {
|
||||
arrow1Ref.current = arrow1
|
||||
|
||||
@ -110,11 +110,11 @@ export default function SecondOption() {
|
||||
// HTTP POST 요청 보내기
|
||||
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
|
||||
toastUp({ message: getMessage(res.returnMessage), type: 'success' })
|
||||
setAdsorptionRange(option.range)
|
||||
})
|
||||
} catch (error) {
|
||||
toastUp({ message: getMessage(res.returnMessage), type: 'error' })
|
||||
}
|
||||
setAdsorptionRange(option.range)
|
||||
}
|
||||
return (
|
||||
<>
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
'use client'
|
||||
import { Fragment, useState } from 'react'
|
||||
import { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { usePathname, useRouter } from 'next/navigation'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { dimmedStore, sessionStore } from '@/store/commonAtom'
|
||||
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { logout } from '@/lib/authActions'
|
||||
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { dimmedStore } from '@/store/commonAtom'
|
||||
|
||||
export const ToggleonMouse = (e, act, target) => {
|
||||
const listWrap = e.target.closest(target)
|
||||
@ -25,7 +28,8 @@ export const ToggleonMouse = (e, act, target) => {
|
||||
}
|
||||
|
||||
export default function Header(props) {
|
||||
const { loginedUserNm } = props
|
||||
const { userSession } = props
|
||||
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
||||
const { getMessage } = useMessage()
|
||||
const pathName = usePathname()
|
||||
// if (pathName.includes('login') || pathName.includes('join')) {
|
||||
@ -65,6 +69,14 @@ export default function Header(props) {
|
||||
},
|
||||
]
|
||||
|
||||
const syncSession = useCallback(() => {
|
||||
setSessionState({ ...userSession })
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
syncSession()
|
||||
}, [userSession])
|
||||
|
||||
const onChangeSelect = (option) => {
|
||||
setSelected(option)
|
||||
}
|
||||
@ -125,7 +137,7 @@ export default function Header(props) {
|
||||
</div>
|
||||
<div className="header-left">
|
||||
<div className="profile-box">
|
||||
<button className="profile">{loginedUserNm}</button>
|
||||
<button className="profile">{userSession.userNm}</button>
|
||||
</div>
|
||||
<div className="sign-out-box">
|
||||
<button className="sign-out" onClick={() => logout()}>
|
||||
|
||||
45
src/hooks/useAdsorptionPoint.js
Normal file
45
src/hooks/useAdsorptionPoint.js
Normal file
@ -0,0 +1,45 @@
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { adsorptionPointAddModeState, adsorptionPointModeState, adsorptionRangeState, canvasState } from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
import { useMouse } from '@/hooks/useMouse'
|
||||
|
||||
export function useAdsorptionPoint() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState)
|
||||
const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState)
|
||||
const [adsorptionRange, setAdsorptionRange] = useRecoilState(adsorptionRangeState)
|
||||
|
||||
const { getIntersectMousePoint } = useMouse()
|
||||
|
||||
const getAdsorptionPoints = () => {
|
||||
return canvas.getObjects().filter((obj) => obj.visible && obj.name === 'adsorptionPoint')
|
||||
}
|
||||
|
||||
const adsorptionPointAddModeStateEvent = (opt) => {
|
||||
//흡착점 모드일 경우
|
||||
let pointer = getIntersectMousePoint(opt)
|
||||
|
||||
const adsorptionPoint = new fabric.Circle({
|
||||
radius: 3,
|
||||
fill: 'red',
|
||||
left: pointer.x - 3,
|
||||
top: pointer.y - 3,
|
||||
x: pointer.x,
|
||||
y: pointer.y,
|
||||
selectable: false,
|
||||
name: 'adsorptionPoint',
|
||||
})
|
||||
|
||||
canvas.add(adsorptionPoint)
|
||||
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
return {
|
||||
adsorptionPointAddMode,
|
||||
adsorptionPointMode,
|
||||
adsorptionRange,
|
||||
getAdsorptionPoints,
|
||||
adsorptionPointAddModeStateEvent,
|
||||
}
|
||||
}
|
||||
51
src/hooks/useDotLineGrid.js
Normal file
51
src/hooks/useDotLineGrid.js
Normal file
@ -0,0 +1,51 @@
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||
import { canvasState, dotLineGridSettingState, dotLineIntervalSelector } from '@/store/canvasAtom'
|
||||
import { calculateDistance } from '@/util/canvas-util'
|
||||
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
|
||||
|
||||
export function useDotLineGrid() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState)
|
||||
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격
|
||||
|
||||
const { adsorptionRange } = useAdsorptionPoint()
|
||||
|
||||
const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState)
|
||||
|
||||
const getLineGrids = () => {
|
||||
return canvas.getObjects().filter((obj) => obj.name === 'lineGrid')
|
||||
}
|
||||
|
||||
const getClosestLineGrid = (point) => {
|
||||
const lines = getLineGrids()
|
||||
if (lines.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
let closestLine = null
|
||||
let minDistance = Infinity
|
||||
|
||||
lines.forEach((line) => {
|
||||
const distance = calculateDistance(point, line)
|
||||
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
closestLine = line
|
||||
}
|
||||
})
|
||||
|
||||
if (minDistance > adsorptionRange) {
|
||||
return null
|
||||
}
|
||||
|
||||
return closestLine
|
||||
}
|
||||
|
||||
return {
|
||||
dotLineGridSetting,
|
||||
resetDotLineGridSetting,
|
||||
getLineGrids,
|
||||
getClosestLineGrid,
|
||||
interval,
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,10 @@ import {
|
||||
currentMenuState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
import { calculateIntersection, distanceBetweenPoints } from '@/util/canvas-util'
|
||||
import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
|
||||
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
|
||||
import { useMouse } from '@/hooks/useMouse'
|
||||
import { useDotLineGrid } from '@/hooks/useDotLineGrid'
|
||||
|
||||
export function useEvent() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
@ -17,10 +20,9 @@ export function useEvent() {
|
||||
const keyboardEventListeners = useRef([])
|
||||
const mouseEventListeners = useRef([])
|
||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
|
||||
const adsorptionRange = useRecoilValue(adsorptionRangeState)
|
||||
|
||||
const { adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, getAdsorptionPoints, adsorptionPointAddModeStateEvent } = useAdsorptionPoint()
|
||||
const { dotLineGridSetting, interval, getClosestLineGrid } = useDotLineGrid()
|
||||
useEffect(() => {
|
||||
if (!canvas) {
|
||||
return
|
||||
@ -35,7 +37,7 @@ export function useEvent() {
|
||||
canvas?.on('mouse:wheel', wheelEvent)
|
||||
|
||||
addDefaultEvent()
|
||||
}, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange])
|
||||
}, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, dotLineGridSetting])
|
||||
|
||||
const addDefaultEvent = () => {
|
||||
//default Event 추가
|
||||
@ -53,26 +55,6 @@ export function useEvent() {
|
||||
e.stopPropagation()
|
||||
}
|
||||
|
||||
const adsorptionPointAddModeStateEvent = (opt) => {
|
||||
//흡착점 모드일 경우
|
||||
let pointer = getIntersectMousePoint(opt)
|
||||
|
||||
const adsorptionPoint = new fabric.Circle({
|
||||
radius: 3,
|
||||
fill: 'red',
|
||||
left: pointer.x - 3,
|
||||
top: pointer.y - 3,
|
||||
x: pointer.x,
|
||||
y: pointer.y,
|
||||
selectable: false,
|
||||
name: 'adsorptionPoint',
|
||||
})
|
||||
|
||||
canvas.add(adsorptionPoint)
|
||||
|
||||
canvas.renderAll()
|
||||
}
|
||||
|
||||
const wheelEvent = (opt) => {
|
||||
const delta = opt.e.deltaY // 휠 이동 값 (양수면 축소, 음수면 확대)
|
||||
let zoom = canvas.getZoom() // 현재 줌 값
|
||||
@ -107,17 +89,61 @@ export function useEvent() {
|
||||
let arrivalPoint = { x: pointer.x, y: pointer.y }
|
||||
|
||||
if (adsorptionPointMode) {
|
||||
// pointer와 adsorptionPoints의 거리를 계산하여 가장 가까운 점을 찾는다.
|
||||
let minDistance = adsorptionRange
|
||||
let adsorptionPoint = null
|
||||
adsorptionPoints.forEach((point) => {
|
||||
const distance = distanceBetweenPoints(pointer, point)
|
||||
if (distance < minDistance) {
|
||||
minDistance = distance
|
||||
adsorptionPoint = point
|
||||
if (dotLineGridSetting.LINE) {
|
||||
const closestLine = getClosestLineGrid(pointer)
|
||||
|
||||
if (closestLine) {
|
||||
const distance = calculateDistance(pointer, closestLine)
|
||||
|
||||
if (distance < adsorptionRange) {
|
||||
arrivalPoint = closestLine.direction === 'vertical' ? { x: closestLine.x1, y: pointer.y } : { x: pointer.x, y: closestLine.y1 }
|
||||
}
|
||||
}
|
||||
})
|
||||
if (adsorptionPoint) {
|
||||
}
|
||||
|
||||
if (dotLineGridSetting.DOT) {
|
||||
const horizontalInterval = interval.horizontalInterval
|
||||
const verticalInterval = interval.verticalInterval
|
||||
|
||||
const x = pointer.x - horizontalInterval * Math.floor(pointer.x / horizontalInterval)
|
||||
const y = pointer.y - verticalInterval * Math.floor(pointer.y / verticalInterval)
|
||||
|
||||
const xRate = (x / horizontalInterval) * 100
|
||||
const yRate = (y / verticalInterval) * 100
|
||||
|
||||
let tempPoint
|
||||
|
||||
if (xRate <= adsorptionRange && yRate <= adsorptionRange) {
|
||||
tempPoint = {
|
||||
x: Math.round(pointer.x / horizontalInterval) * horizontalInterval + horizontalInterval / 2,
|
||||
y: Math.round(pointer.y / verticalInterval) * verticalInterval + horizontalInterval / 2,
|
||||
}
|
||||
} else if (xRate <= adsorptionRange && yRate >= adsorptionRange) {
|
||||
tempPoint = {
|
||||
x: Math.round(pointer.x / horizontalInterval) * horizontalInterval + horizontalInterval / 2,
|
||||
y: Math.round(pointer.y / verticalInterval) * verticalInterval - horizontalInterval / 2,
|
||||
}
|
||||
} else if (xRate >= adsorptionRange && yRate <= adsorptionRange) {
|
||||
tempPoint = {
|
||||
x: Math.round(pointer.x / horizontalInterval) * horizontalInterval - horizontalInterval / 2,
|
||||
y: Math.round(pointer.y / verticalInterval) * verticalInterval + horizontalInterval / 2,
|
||||
}
|
||||
} else if (xRate >= adsorptionRange && yRate >= adsorptionRange) {
|
||||
tempPoint = {
|
||||
x: Math.round(pointer.x / horizontalInterval) * horizontalInterval - horizontalInterval / 2,
|
||||
y: Math.round(pointer.y / verticalInterval) * verticalInterval - horizontalInterval / 2,
|
||||
}
|
||||
}
|
||||
|
||||
if (distanceBetweenPoints(pointer, tempPoint) <= adsorptionRange) {
|
||||
arrivalPoint = tempPoint
|
||||
}
|
||||
}
|
||||
|
||||
// pointer와 adsorptionPoints의 거리를 계산하여 가장 가까운 점을 찾는다.
|
||||
let adsorptionPoint = findClosestPoint(pointer, adsorptionPoints)
|
||||
|
||||
if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) <= adsorptionRange) {
|
||||
arrivalPoint = { ...adsorptionPoint }
|
||||
}
|
||||
}
|
||||
@ -203,28 +229,11 @@ export function useEvent() {
|
||||
})
|
||||
}
|
||||
|
||||
const getAdsorptionPoints = () => {
|
||||
return canvas.getObjects().filter((obj) => obj.visible && obj.name === 'adsorptionPoint')
|
||||
}
|
||||
|
||||
//가로선, 세로선의 교차점을 return
|
||||
const getIntersectMousePoint = (e) => {
|
||||
let pointer = canvas.getPointer(e.e)
|
||||
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
|
||||
|
||||
if (mouseLines.length < 2) {
|
||||
return pointer
|
||||
}
|
||||
|
||||
return calculateIntersection(mouseLines[0], mouseLines[1]) ?? pointer
|
||||
}
|
||||
|
||||
return {
|
||||
addDocumentEventListener,
|
||||
addCanvasMouseEventListener,
|
||||
removeAllMouseEventListeners,
|
||||
removeAllDocumentEventListeners,
|
||||
removeMouseEvent,
|
||||
getIntersectMousePoint,
|
||||
}
|
||||
}
|
||||
|
||||
23
src/hooks/useMouse.js
Normal file
23
src/hooks/useMouse.js
Normal file
@ -0,0 +1,23 @@
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { calculateIntersection } from '@/util/canvas-util'
|
||||
|
||||
export function useMouse() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
//가로선, 세로선의 교차점을 return
|
||||
const getIntersectMousePoint = (e) => {
|
||||
let pointer = canvas.getPointer(e.e)
|
||||
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
|
||||
|
||||
if (mouseLines.length < 2) {
|
||||
return pointer
|
||||
}
|
||||
|
||||
return calculateIntersection(mouseLines[0], mouseLines[1]) || pointer
|
||||
}
|
||||
|
||||
return {
|
||||
getIntersectMousePoint,
|
||||
}
|
||||
}
|
||||
@ -205,7 +205,7 @@ export const verticalHorizontalModeState = atom({
|
||||
// 흡착점 모드
|
||||
export const adsorptionPointModeState = atom({
|
||||
key: 'adsorptionPointModeState',
|
||||
default: false,
|
||||
default: true,
|
||||
})
|
||||
// 흡착점 추가모드
|
||||
export const adsorptionPointAddModeState = atom({
|
||||
@ -218,3 +218,35 @@ export const adsorptionRangeState = atom({
|
||||
key: 'adsorptionRangeState',
|
||||
default: 50,
|
||||
})
|
||||
|
||||
// 점,선 그리드 설정
|
||||
export const dotLineGridSettingState = atom({
|
||||
key: 'gridSettingState',
|
||||
default: {
|
||||
INTERVAL: {
|
||||
type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격
|
||||
ratioInterval: 910,
|
||||
verticalInterval: 910,
|
||||
horizontalInterval: 910,
|
||||
dimension: 1, // 치수
|
||||
},
|
||||
DOT: false,
|
||||
LINE: false,
|
||||
},
|
||||
})
|
||||
|
||||
export const dotLineIntervalSelector = selector({
|
||||
key: 'dotLineIntervalSelector',
|
||||
get: ({ get }) => {
|
||||
const gridSetting = get(dotLineGridSettingState)
|
||||
return gridSetting.INTERVAL.type === 1
|
||||
? {
|
||||
horizontalInterval: Math.round(gridSetting.INTERVAL.horizontalInterval / 10),
|
||||
verticalInterval: Math.round(gridSetting.INTERVAL.verticalInterval / 10),
|
||||
}
|
||||
: {
|
||||
horizontalInterval: Math.round((gridSetting.INTERVAL.ratioInterval * gridSetting.INTERVAL.dimension) / 10),
|
||||
verticalInterval: Math.round((gridSetting.INTERVAL.ratioInterval * gridSetting.INTERVAL.dimension) / 10),
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
@ -39,9 +39,9 @@ export const settingModalSecondOptionsState = atom({
|
||||
],
|
||||
option4: [
|
||||
{ id: 1, column: 'adsorpRangeSmall', name: 'modal.canvas.setting.font.plan.absorption.small', selected: true, range: 10 },
|
||||
{ id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false, range: 30 },
|
||||
{ id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false, range: 50 },
|
||||
{ id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false, range: 80 },
|
||||
{ id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false, range: 20 },
|
||||
{ id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false, range: 30 },
|
||||
{ id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false, range: 40 },
|
||||
],
|
||||
},
|
||||
dangerouslyAllowMutability: true,
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
export const onlyNumberInputChange = (e, callback) => {
|
||||
let value = e.target.value.replace(/^0+/, '')
|
||||
value = value.replace(/[^-0-9]/g, '')
|
||||
callback(value)
|
||||
callback(value, e)
|
||||
}
|
||||
|
||||
//소수점 둘째자리 숫자만 입력가능
|
||||
@ -12,9 +12,9 @@ export const onlyNumberWithDotInputChange = (e, callback) => {
|
||||
const pattern = /^-?(\d{1,4}([.]\d{0,2})?)?$/
|
||||
if (!pattern.test(val)) {
|
||||
// prev에서 마지막 자리 제거
|
||||
callback(val.slice(0, val.length - 1))
|
||||
callback(val.slice(0, val.length - 1), e)
|
||||
return
|
||||
}
|
||||
|
||||
callback(val)
|
||||
callback(val, e)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user