선속성 작업중

This commit is contained in:
yjnoh 2024-11-11 10:19:40 +09:00
parent 21d758834d
commit 86d9e574bb
6 changed files with 210 additions and 29 deletions

View File

@ -161,6 +161,7 @@ export const SAVE_KEY = [
'groupId', 'groupId',
'planeSize', 'planeSize',
'actualSize', 'actualSize',
'surfaceId',
] ]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]

View File

@ -5,14 +5,18 @@ import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom' import { contextPopupPositionState } from '@/store/popupAtom'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
export default function FlowDirectionSetting(props) { export default function FlowDirectionSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState) const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, pos = contextPopupPosition, target } = props const { id, pos = contextPopupPosition, target } = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const [compasDeg, setCompasDeg] = useState(360) const [compasDeg, setCompasDeg] = useState(360)
const [flowDirection, setFlowDirection] = useState(target.direction)
const { changeSurfaceFlowDirection } = useSurfaceShapeBatch()
const orientations = [ const orientations = [
// { name: `${getMessage('commons.none')}`, value: 0 },
{ name: `${getMessage('commons.south')}`, value: 360 }, { name: `${getMessage('commons.south')}`, value: 360 },
{ name: `${getMessage('commons.south')}${getMessage('commons.east')}`, value: 315 }, { name: `${getMessage('commons.south')}${getMessage('commons.east')}`, value: 315 },
{ name: `${getMessage('commons.south')}${getMessage('commons.west')}`, value: 45 }, { name: `${getMessage('commons.south')}${getMessage('commons.west')}`, value: 45 },
@ -75,13 +79,13 @@ export default function FlowDirectionSetting(props) {
<div className="object-direction-wrap"> <div className="object-direction-wrap">
<div className="plane-direction"> <div className="plane-direction">
<span className="top">{getMessage('commons.north')}</span> <span className="top">{getMessage('commons.north')}</span>
<button className="plane-btn up"></button> <button className={`plane-btn up ${flowDirection === 'north' ? 'act' : ''}`} onClick={() => setFlowDirection('north')}></button>
<span className="right">{getMessage('commons.east')}</span> <span className="right">{getMessage('commons.east')}</span>
<button className="plane-btn right"></button> <button className={`plane-btn right ${flowDirection === 'east' ? 'act' : ''}`} onClick={() => setFlowDirection('east')}></button>
<span className="bottom">{getMessage('commons.south')}</span> <span className="bottom">{getMessage('commons.south')}</span>
<button className="plane-btn down act"></button> <button className={`plane-btn down ${flowDirection === 'south' ? 'act' : ''}`} onClick={() => setFlowDirection('south')}></button>
<span className="left">{getMessage('commons.west')}</span> <span className="left">{getMessage('commons.west')}</span>
<button className="plane-btn left"></button> <button className={`plane-btn left ${flowDirection === 'west' ? 'act' : ''}`} onClick={() => setFlowDirection('west')}></button>
</div> </div>
</div> </div>
</div> </div>
@ -111,18 +115,14 @@ export default function FlowDirectionSetting(props) {
key={index} key={index}
className={`circle ${compasDeg === 15 * (12 + index) ? 'act' : ''}`} className={`circle ${compasDeg === 15 * (12 + index) ? 'act' : ''}`}
onClick={() => setCompasDeg(15 * (12 + index))} onClick={() => setCompasDeg(15 * (12 + index))}
> ></div>
<i>{13 - index}</i>
</div>
))} ))}
{Array.from({ length: 180 / 15 - 1 }).map((dot, index) => ( {Array.from({ length: 180 / 15 - 1 }).map((dot, index) => (
<div <div
key={index} key={index}
className={`circle ${compasDeg === 15 * (index + 1) ? 'act' : ''}`} className={`circle ${compasDeg === 15 * (index + 1) ? 'act' : ''}`}
onClick={() => setCompasDeg(15 * (index + 1))} onClick={() => setCompasDeg(15 * (index + 1))}
> ></div>
<i>{24 - index}</i>
</div>
))} ))}
<div className="compas"> <div className="compas">
<div className="compas-arr" style={{ transform: `rotate(${compasDeg}deg)` }}></div> <div className="compas-arr" style={{ transform: `rotate(${compasDeg}deg)` }}></div>
@ -133,7 +133,9 @@ export default function FlowDirectionSetting(props) {
</div> </div>
</div> </div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button> <button className="btn-frame modal act" onClick={() => changeSurfaceFlowDirection(target, flowDirection, selectedOrientation)}>
{getMessage('modal.common.save')}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,13 +3,18 @@ import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom' import { contextPopupPositionState } from '@/store/popupAtom'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useState } from 'react' import { useState, useEffect } from 'react'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
import { useEvent } from '@/hooks/useEvent'
export default function LinePropertySetting(props) { export default function LinePropertySetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState) const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, pos = contextPopupPosition } = props const { id, pos = contextPopupPosition, target } = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { changeSurfaceLinePropertyEvent, changeSurfaceLineProperty } = useSurfaceShapeBatch()
const { initEvent } = useEvent()
const properties = [ const properties = [
{ name: getMessage('eaves.line'), value: 'eaves' }, { name: getMessage('eaves.line'), value: 'eaves' },
{ name: getMessage('ridge'), value: 'ridge' }, { name: getMessage('ridge'), value: 'ridge' },
@ -29,6 +34,14 @@ export default function LinePropertySetting(props) {
{ name: getMessage('no.setting'), value: 'noSetting' }, { name: getMessage('no.setting'), value: 'noSetting' },
] ]
const [selectedProperty, setSelectedProperty] = useState(null) const [selectedProperty, setSelectedProperty] = useState(null)
useEffect(() => {
changeSurfaceLinePropertyEvent(target)
return () => {
initEvent()
}
}, [])
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}> <div className={`modal-pop-wrap r mount`}>
@ -66,7 +79,9 @@ export default function LinePropertySetting(props) {
</div> </div>
</div> </div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button> <button className="btn-frame modal act" onClick={() => changeSurfaceLineProperty(selectedProperty)}>
{getMessage('modal.common.save')}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -13,6 +13,8 @@ import { usePopup } from '@/hooks/usePopup'
import { roofDisplaySelector } from '@/store/settingAtom' import { roofDisplaySelector } from '@/store/settingAtom'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { fontSelector } from '@/store/fontAtom' import { fontSelector } from '@/store/fontAtom'
import { slopeSelector } from '@/store/commonAtom'
import { QLine } from '@/components/fabric/QLine'
export function useSurfaceShapeBatch() { export function useSurfaceShapeBatch() {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -22,6 +24,7 @@ export function useSurfaceShapeBatch() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const globalPitch = useRecoilValue(globalPitchState) const globalPitch = useRecoilValue(globalPitchState)
const roofDisplay = useRecoilValue(roofDisplaySelector) const roofDisplay = useRecoilValue(roofDisplaySelector)
const slope = useRecoilValue(slopeSelector(globalPitch))
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { addCanvasMouseEventListener, initEvent } = useEvent() const { addCanvasMouseEventListener, initEvent } = useEvent()
const { closePopup } = usePopup() const { closePopup } = usePopup()
@ -126,6 +129,7 @@ export function useSurfaceShapeBatch() {
addCanvasMouseEventListener('mouse:down', (e) => { addCanvasMouseEventListener('mouse:down', (e) => {
isDrawing = false isDrawing = false
obj.set('name', POLYGON_TYPE.ROOF) obj.set('name', POLYGON_TYPE.ROOF)
obj.set('surfaceId', surfaceId)
initEvent() initEvent()
setSurfaceShapePattern(obj, roofDisplay.column) setSurfaceShapePattern(obj, roofDisplay.column)
closePopup(id) closePopup(id)
@ -580,18 +584,19 @@ export function useSurfaceShapeBatch() {
text: '배치면 내용을 전부 삭제하시겠습니까?', text: '배치면 내용을 전부 삭제하시겠습니까?',
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
canvas?.getObjects().forEach((obj) => { // canvas?.getObjects().forEach((obj) => {
if ( // if (
obj.name === POLYGON_TYPE.ROOF || // obj.name === POLYGON_TYPE.ROOF ||
obj.name === BATCH_TYPE.OPENING || // obj.name === BATCH_TYPE.OPENING ||
obj.name === BATCH_TYPE.SHADOW || // obj.name === BATCH_TYPE.SHADOW ||
obj.name === BATCH_TYPE.TRIANGLE_DORMER || // obj.name === BATCH_TYPE.TRIANGLE_DORMER ||
obj.name === BATCH_TYPE.PENTAGON_DORMER || // obj.name === BATCH_TYPE.PENTAGON_DORMER ||
obj.name === 'lengthText' // obj.name === 'lengthText'
) { // ) {
canvas?.remove(obj) // canvas?.remove(obj)
} // }
}) // })
canvas.clear()
swalFire({ text: '삭제 완료 되었습니다.' }) swalFire({ text: '삭제 완료 되었습니다.' })
}, },
// denyFn: () => { // denyFn: () => {
@ -823,10 +828,159 @@ export function useSurfaceShapeBatch() {
canvas.renderAll() canvas.renderAll()
} }
const surfaceShapeActualSize = () => {
const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof')
let notParallelLines = []
const roofArray = []
roofs.forEach((obj) => {
const roof = {
id: obj.id,
surfaceId: obj.surfaceId,
targetLines: [],
baseLines: [],
direction: obj.direction,
}
obj.lines.forEach((line) => {
if (obj.direction === 'north' || obj.direction === 'south') {
if (line.y1 !== line.y2) {
roof.targetLines.push(line)
} else {
roof.baseLines.push(line)
}
} else {
if (line.x1 !== line.x2) {
roof.targetLines.push(line)
} else {
roof.baseLines.push(line)
}
}
})
roofArray.push(roof)
})
const slopeRadians = slope.angleValue * (Math.PI / 180)
const tanSlope = Math.tan(slopeRadians)
roofArray.forEach((roof) => {
roof.targetLines.forEach((line) => {
let calcLength = line.length
if (roof.surfaceId === 1) {
calcLength = roof.direction === 'north' || roof.direction === 'south' ? Math.abs(line.y1 - line.y2) : Math.abs(line.x1 - line.x2)
}
const h = calcLength * tanSlope
const resultLength = Math.sqrt(Math.pow(calcLength, 2) + Math.pow(h, 2))
line.set({
attributes: {
...line.attributes,
actualSize: parseInt((Math.floor(resultLength) * 10).toFixed(0)),
planeSize: parseInt(line.length * 10),
},
})
})
roof.baseLines.forEach((line) => {
line.set({
attributes: {
...line.attributes,
actualSize: parseInt((Math.floor(line.length) * 10).toFixed(0)),
planeSize: parseInt(line.length * 10),
},
})
})
})
}
const changeSurfaceLinePropertyEvent = (roof) => {
let tmpLines = []
roof.set({
selectable: false,
})
canvas.discardActiveObject()
roof.lines.forEach((obj, index) => {
const tmpLine = new QLine([obj.x1, obj.y1, obj.x2, obj.y2], {
...obj,
stroke: 'rgb(3, 255, 0)',
strokeWidth: 8,
selectable: true,
name: 'lineProperty',
index: index,
})
tmpLines.push(tmpLine)
canvas.add(tmpLine)
})
addCanvasMouseEventListener('mouse:down', (e) => {
const selectedLine = e.target
if (selectedLine) {
selectedLine.set({
stroke: 'red',
name: 'selectedLineProperty',
})
tmpLines.forEach((line) => {
if (line.index !== selectedLine.index) {
line.set({
stroke: 'rgb(3, 255, 0)',
name: 'lineProperty',
})
}
})
} else {
tmpLines.forEach((line) => {
line.set({
stroke: 'rgb(3, 255, 0)',
name: 'lineProperty',
})
})
}
})
canvas.renderAll()
}
const changeSurfaceLineProperty = (property) => {
console.log(property)
if (!property) {
swalFire({ text: getMessage('modal.line.property.change'), icon: 'error' })
return
}
const selectedLine = canvas.getActiveObjects()
if (selectedLine && selectedLine[0].name === 'selectedLineProperty') {
swalFire({
text: getMessage('modal.line.property.change.confirm'),
type: 'confirm',
confirmFn: () => {
selectedLine.set({
type: property.value,
})
},
})
} else {
swalFire({ text: getMessage('modal.line.property.change.unselect'), icon: 'error' })
}
}
const changeSurfaceFlowDirection = (roof, direction, orientation) => {
roof.set({
direction: direction,
})
drawDirectionArrow(roof)
canvas?.renderAll()
}
return { return {
applySurfaceShape, applySurfaceShape,
deleteAllSurfacesAndObjects, deleteAllSurfacesAndObjects,
moveSurfaceShapeBatch, moveSurfaceShapeBatch,
resizeSurfaceShapeBatch, resizeSurfaceShapeBatch,
surfaceShapeActualSize,
changeSurfaceFlowDirection,
changeSurfaceLinePropertyEvent,
changeSurfaceLineProperty,
} }
} }

View File

@ -51,7 +51,7 @@ export function useContextMenu() {
const [column, setColumn] = useState(null) const [column, setColumn] = useState(null)
const { handleZoomClear } = useCanvasEvent() const { handleZoomClear } = useCanvasEvent()
const { moveObjectBatch } = useObjectBatch({}) const { moveObjectBatch } = useObjectBatch({})
const { moveSurfaceShapeBatch } = useSurfaceShapeBatch() const { moveSurfaceShapeBatch, surfaceShapeActualSize } = useSurfaceShapeBatch()
const currentMenuSetting = () => { const currentMenuSetting = () => {
switch (currentMenu) { switch (currentMenu) {
case MENU.PLAN_DRAWING: case MENU.PLAN_DRAWING:
@ -303,6 +303,11 @@ export function useContextMenu() {
case 'roof': case 'roof':
setContextMenu([ setContextMenu([
[ [
{
id: 'surfaceShapeActualSize',
name: '면형상 실측',
fn: () => surfaceShapeActualSize(),
},
{ {
id: 'sizeEdit', id: 'sizeEdit',
name: '사이즈 변경', name: '사이즈 변경',
@ -336,7 +341,7 @@ export function useContextMenu() {
{ {
id: 'linePropertyEdit', id: 'linePropertyEdit',
name: getMessage('contextmenu.line.property.edit'), name: getMessage('contextmenu.line.property.edit'),
component: <LinePropertySetting id={popupId} />, component: <LinePropertySetting id={popupId} target={currentObject} />,
}, },
{ {
id: 'flowDirectionEdit', id: 'flowDirectionEdit',

View File

@ -400,6 +400,9 @@
"modal.module.circuit.number.edit": "모듈 일괄 회로 번호 변경", "modal.module.circuit.number.edit": "모듈 일괄 회로 번호 변경",
"modal.module.circuit.number.edit.info": "회로 번호를 입력해주세요.", "modal.module.circuit.number.edit.info": "회로 번호를 입력해주세요.",
"modal.module.circuit.number": "회로 번호", "modal.module.circuit.number": "회로 번호",
"modal.line.property.change": "변경할 속성을 선택해 주세요.",
"modal.line.property.change.unselect": "변경할 라인을 선택해 주세요.",
"modal.line.property.change.confirm": "속성을 변경하시겠습니까?",
"common.message.no.data": "No data", "common.message.no.data": "No data",
"common.message.no.dataDown": "No data to download", "common.message.no.dataDown": "No data to download",
"common.message.noData": "No data to display", "common.message.noData": "No data to display",
@ -495,6 +498,7 @@
"commons.east": "동", "commons.east": "동",
"commons.south": "남", "commons.south": "남",
"commons.north": "북", "commons.north": "북",
"commons.none": "선택안함",
"font.style.normal": "보통", "font.style.normal": "보통",
"font.style.italic": "기울임꼴", "font.style.italic": "기울임꼴",
"font.style.bold": "굵게", "font.style.bold": "굵게",