1. 외벽선그리기, 배치면그리기 에서 흡착점 동작

2. 외벽선그리기, 배치면그리기 에서 그리드, 흡착점 선택 불가
3. 이동, 복사 시 길이 줄어듬
4. 옵션 설정 닫을 때, 임의그리드,흡착점 선택  해제
This commit is contained in:
hyojun.choi 2025-05-20 17:02:56 +09:00
parent 4bbe99bda8
commit 4ec191dcb0
7 changed files with 117 additions and 104 deletions

View File

@ -105,6 +105,16 @@ export default function GridOption(props) {
initEvent() initEvent()
}, [gridOptions]) }, [gridOptions])
useEffect(() => {
return () => {
setAdsorptionPointAddMode(false)
setTempGridMode(false)
setTimeout(() => {
initEvent()
}, 100)
}
}, [])
const dotLineGridProps = { const dotLineGridProps = {
id: dotLineId, id: dotLineId,
setIsShow: setShowDotLineGridModal, setIsShow: setShowDotLineGridModal,

View File

@ -6,16 +6,22 @@ import WithDraggable from '@/components/common/draggable/WithDraggable'
import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption' import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import GridOption from '@/components/floor-plan/modal/setting01/GridOption' import GridOption from '@/components/floor-plan/modal/setting01/GridOption'
import { canGridOptionSeletor } from '@/store/canvasAtom' import { adsorptionPointAddModeState, canGridOptionSeletor, tempGridModeState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { useTempGrid } from '@/hooks/useTempGrid'
import { settingModalGridOptionsState } from '@/store/settingAtom'
import { useEvent } from '@/hooks/useEvent'
export default function SettingModal01(props) { export default function SettingModal01(props) {
const { id } = props const { id } = props
const [buttonAct, setButtonAct] = useState(1) const [buttonAct, setButtonAct] = useState(1)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor) const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor)
const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState)
const [tempGridMode, setTempGridMode] = useRecoilState(tempGridModeState)
const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState)
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { const {
@ -71,9 +77,22 @@ export default function SettingModal01(props) {
setButtonAct(num) setButtonAct(num)
} }
const onClose = () => {
setTempGridMode(false)
setAdsorptionPointAddMode(false)
setGridOptions((prev) => {
const newSettingOptions = [...prev]
newSettingOptions[0].selected = false
newSettingOptions[2].selected = false
return [...newSettingOptions]
})
closePopup(id, true)
}
return ( return (
<WithDraggable isShow={true} pos={{ x: 1275, y: 180 }} className="sm"> <WithDraggable isShow={true} pos={{ x: 1275, y: 180 }} className="sm">
<WithDraggable.Header title={getMessage('modal.canvas.setting')} onClose={() => closePopup(id, true)} /> <WithDraggable.Header title={getMessage('modal.canvas.setting')} onClose={onClose} />
<WithDraggable.Body> <WithDraggable.Body>
<div className="modal-btn-wrap"> <div className="modal-btn-wrap">
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => handleBtnClick(1)}> <button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => handleBtnClick(1)}>

View File

@ -153,18 +153,18 @@ export function useGrid() {
const move = (object, x, y) => { const move = (object, x, y) => {
object.set({ object.set({
...object, ...object,
x1: object.direction === 'vertical' ? object.x1 + x : 0, x1: object.direction === 'vertical' ? object.x1 + x : -1500,
x2: object.direction === 'vertical' ? object.x1 + x : canvas.width, x2: object.direction === 'vertical' ? object.x1 + x : 2500,
y1: object.direction === 'vertical' ? 0 : object.y1 + y, y1: object.direction === 'vertical' ? -1500 : object.y1 + y,
y2: object.direction === 'vertical' ? canvas.height : object.y1 + y, y2: object.direction === 'vertical' ? 2500 : object.y1 + y,
}) })
} }
const copy = (object, length) => { const copy = (object, length) => {
const lineStartX = object.direction === 'vertical' ? object.x1 + length : 0 const lineStartX = object.direction === 'vertical' ? object.x1 + length : -1500
const lineEndX = object.direction === 'vertical' ? object.x2 + length : canvas.width const lineEndX = object.direction === 'vertical' ? object.x2 + length : 2500
const lineStartY = object.direction === 'vertical' ? 0 : object.y1 + length const lineStartY = object.direction === 'vertical' ? -1500 : object.y1 + length
const lineEndY = object.direction === 'vertical' ? canvas.width : object.y1 + length const lineEndY = object.direction === 'vertical' ? 2500 : object.y1 + length
const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], { const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], {
stroke: gridColor, stroke: gridColor,

View File

@ -33,6 +33,7 @@ import { usePopup } from '@/hooks/usePopup'
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting' import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
import Big from 'big.js' import Big from 'big.js'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import { useObject } from '@/hooks/useObject'
//외벽선 그리기 //외벽선 그리기
export function useOuterLineWall(id, propertiesId) { export function useOuterLineWall(id, propertiesId) {
@ -57,6 +58,7 @@ export function useOuterLineWall(id, propertiesId) {
const { addLine, removeLine } = useLine() const { addLine, removeLine } = useLine()
const { tempGridMode } = useTempGrid() const { tempGridMode } = useTempGrid()
const { addPolygonByLines } = usePolygon() const { addPolygonByLines } = usePolygon()
const { handleSelectableObjects } = useObject()
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState) const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
@ -91,18 +93,16 @@ export function useOuterLineWall(id, propertiesId) {
const isFix = useRef(false) const isFix = useRef(false)
useEffect(() => { useEffect(() => {
if (adsorptionPointAddMode || tempGridMode) {
return
}
addCanvasMouseEventListener('mouse:down', mouseDown) addCanvasMouseEventListener('mouse:down', mouseDown)
addDocumentEventListener('contextmenu', document, (e) => { addDocumentEventListener('contextmenu', document, (e) => {
handleRollback() handleRollback()
}) })
handleSelectableObjects(['lineGrid', 'tempGrid', 'adsorptionPoint'], false)
clear() clear()
return () => { return () => {
initEvent() initEvent()
handleSelectableObjects(['lineGrid', 'tempGrid', 'adsorptionPoint'], true)
canvas canvas
.getObjects() .getObjects()

View File

@ -38,28 +38,31 @@ import { roofDisplaySelector } from '@/store/settingAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty' import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useObject } from '@/hooks/useObject'
// 배치면 그리기 // 배치면 그리기
export function usePlacementShapeDrawing(id) { export function usePlacementShapeDrawing(id) {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const roofDisplay = useRecoilValue(roofDisplaySelector) const roofDisplay = useRecoilValue(roofDisplaySelector)
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseLine } = const {
useEvent() initEvent,
addCanvasMouseEventListener,
addDocumentEventListener,
removeAllMouseEventListeners,
removeAllDocumentEventListeners,
removeMouseLine,
} = useEvent()
// const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } = // const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } =
// useContext(EventContext) // useContext(EventContext)
const { getIntersectMousePoint } = useMouse() const { getIntersectMousePoint } = useMouse()
const { addLine, removeLine } = useLine() const { addLine, removeLine } = useLine()
const { addPolygonByLines, drawDirectionArrow } = usePolygon() const { addPolygonByLines, drawDirectionArrow } = usePolygon()
const { tempGridMode } = useTempGrid()
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const { changeSurfaceLineType } = useSurfaceShapeBatch({}) const { changeSurfaceLineType } = useSurfaceShapeBatch({})
const { handleSelectableObjects } = useObject()
const canvasSetting = useRecoilValue(canvasSettingState)
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
const adsorptionPointMode = useRecoilValue(adsorptionPointModeState)
const adsorptionRange = useRecoilValue(adsorptionRangeState) const adsorptionRange = useRecoilValue(adsorptionRangeState)
const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격
const length1Ref = useRef(null) const length1Ref = useRef(null)
const length2Ref = useRef(null) const length2Ref = useRef(null)
@ -87,16 +90,17 @@ export function usePlacementShapeDrawing(id) {
const globalPitch = useRecoilValue(globalPitchState) const globalPitch = useRecoilValue(globalPitchState)
useEffect(() => { useEffect(() => {
if (adsorptionPointAddMode || tempGridMode) {
return
}
addCanvasMouseEventListener('mouse:down', mouseDown) addCanvasMouseEventListener('mouse:down', mouseDown)
addDocumentEventListener('contextmenu', document, (e) => { addDocumentEventListener('contextmenu', document, (e) => {
handleRollback() handleRollback()
}) })
handleSelectableObjects(['lineGrid', 'tempGrid', 'adsorptionPoint'], false)
clear() clear()
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode]) return () => {
initEvent()
handleSelectableObjects(['lineGrid', 'tempGrid', 'adsorptionPoint'], true)
}
}, [])
useEffect(() => { useEffect(() => {
setPoints([]) setPoints([])
@ -122,7 +126,6 @@ export function usePlacementShapeDrawing(id) {
}, [type]) }, [type])
const clear = () => { const clear = () => {
addCanvasMouseEventListener('mouse:move', mouseMove)
setLength1(0) setLength1(0)
setLength2(0) setLength2(0)
@ -178,79 +181,6 @@ export function usePlacementShapeDrawing(id) {
} }
} }
/*
mouseMove
*/
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const roofAdsorptionPoints = useRef([])
const intersectionPoints = useRef([])
const { getAdsorptionPoints } = useAdsorptionPoint()
const mouseMove = (e) => {
removeMouseLine()
const pointer = canvas.getPointer(e.e)
const roofsPoints = roofs.map((roof) => roof.points).flat()
roofAdsorptionPoints.current = [...roofsPoints]
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed)
const otherAdsorptionPoints = []
auxiliaryLines.forEach((line1) => {
auxiliaryLines.forEach((line2) => {
if (line1 === line2) {
return
}
const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) {
return
}
otherAdsorptionPoints.push(intersectionPoint)
})
})
let innerLinePoints = []
canvas
.getObjects()
.filter((obj) => obj.innerLines)
.forEach((polygon) => {
polygon.innerLines.forEach((line) => {
innerLinePoints.push({ x: line.x1, y: line.y1 })
innerLinePoints.push({ x: line.x2, y: line.y2 })
})
})
const adsorptionPoints = [
...getAdsorptionPoints(),
...roofAdsorptionPoints.current,
...otherAdsorptionPoints,
...intersectionPoints.current,
...innerLinePoints,
]
let arrivalPoint = { x: pointer.x, y: pointer.y }
let adsorptionPoint = findClosestPoint(pointer, adsorptionPoints)
if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) <= adsorptionRange) {
arrivalPoint = { ...adsorptionPoint }
}
const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], {
stroke: 'red',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
})
const verticalLine = new fabric.Line([arrivalPoint.x, -1 * canvas.height, arrivalPoint.x, 2 * canvas.height], {
stroke: 'red',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
})
canvas?.add(horizontalLine, verticalLine)
canvas?.renderAll()
}
useEffect(() => { useEffect(() => {
canvas canvas
?.getObjects() ?.getObjects()

View File

@ -8,6 +8,7 @@ import { useDotLineGrid } from '@/hooks/useDotLineGrid'
import { useTempGrid } from '@/hooks/useTempGrid' import { useTempGrid } from '@/hooks/useTempGrid'
import { gridColorState } from '@/store/gridAtom' import { gridColorState } from '@/store/gridAtom'
import { gridDisplaySelector } from '@/store/settingAtom' import { gridDisplaySelector } from '@/store/settingAtom'
import { POLYGON_TYPE } from '@/common/common'
export function useEvent() { export function useEvent() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -21,6 +22,8 @@ export function useEvent() {
const { adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, getAdsorptionPoints, adsorptionPointAddModeStateEvent } = useAdsorptionPoint() const { adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, getAdsorptionPoints, adsorptionPointAddModeStateEvent } = useAdsorptionPoint()
const { dotLineGridSetting, interval, getClosestLineGrid } = useDotLineGrid() const { dotLineGridSetting, interval, getClosestLineGrid } = useDotLineGrid()
const { tempGridModeStateLeftClickEvent, tempGridMode } = useTempGrid() const { tempGridModeStateLeftClickEvent, tempGridMode } = useTempGrid()
const roofAdsorptionPoints = useRef([])
const intersectionPoints = useRef([])
const textMode = useRecoilValue(textModeState) const textMode = useRecoilValue(textModeState)
@ -97,14 +100,52 @@ export function useEvent() {
const defaultMouseMoveEvent = (e) => { const defaultMouseMoveEvent = (e) => {
removeMouseLine() removeMouseLine()
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
// 가로선 // 가로선
const pointer = canvas.getPointer(e.e) const pointer = canvas.getPointer(e.e)
const adsorptionPoints = getAdsorptionPoints()
let arrivalPoint = { x: pointer.x, y: pointer.y } let arrivalPoint = { x: pointer.x, y: pointer.y }
if (adsorptionPointMode) { if (adsorptionPointMode) {
const roofsPoints = roofs.map((roof) => roof.points).flat()
roofAdsorptionPoints.current = [...roofsPoints]
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed)
const otherAdsorptionPoints = []
auxiliaryLines.forEach((line1) => {
auxiliaryLines.forEach((line2) => {
if (line1 === line2) {
return
}
const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) {
return
}
otherAdsorptionPoints.push(intersectionPoint)
})
})
let innerLinePoints = []
canvas
.getObjects()
.filter((obj) => obj.innerLines)
.forEach((polygon) => {
polygon.innerLines.forEach((line) => {
innerLinePoints.push({ x: line.x1, y: line.y1 })
innerLinePoints.push({ x: line.x2, y: line.y2 })
})
})
const adsorptionPoints = [
...getAdsorptionPoints(),
...roofAdsorptionPoints.current,
...otherAdsorptionPoints,
...intersectionPoints.current,
...innerLinePoints,
]
if (dotLineGridSetting.LINE || canvas.getObjects().filter((obj) => ['lineGrid', 'tempGrid'].includes(obj.name)).length > 0) { if (dotLineGridSetting.LINE || canvas.getObjects().filter((obj) => ['lineGrid', 'tempGrid'].includes(obj.name)).length > 0) {
const closestLine = getClosestLineGrid(pointer) const closestLine = getClosestLineGrid(pointer)
@ -357,6 +398,7 @@ export function useEvent() {
removeDocumentEvent, removeDocumentEvent,
removeMouseEvent, removeMouseEvent,
removeMouseLine, removeMouseLine,
defaultMouseMoveEvent,
initEvent, initEvent,
} }
} }

View File

@ -12,5 +12,17 @@ export function useObject() {
canvas.remove(item) canvas.remove(item)
}) })
} }
return { deleteObject }
const handleSelectableObjects = (targetNames = [], bool) => {
if (!canvas) {
return
}
const selectableObjects = canvas.getObjects().filter((obj) => targetNames.includes(obj.name))
selectableObjects.forEach((obj) => {
obj.selectable = bool
})
canvas.renderAll()
}
return { deleteObject, handleSelectableObjects }
} }