From f69a473102f760c37043890a491d3da4d9748481 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 24 Oct 2024 18:24:56 +0900 Subject: [PATCH] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/font/FontSetting.jsx | 3 +- .../floor-plan/modal/grid/DotLineGrid.jsx | 192 ++++-------------- src/hooks/common/useCanvasConfigInitialize.js | 63 ++++-- src/hooks/common/useGrid.js | 145 +++++++++++++ src/hooks/usePolygon.js | 17 +- 5 files changed, 244 insertions(+), 176 deletions(-) create mode 100644 src/hooks/common/useGrid.js diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index cbb2de00..48efa316 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -1,11 +1,10 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { usePopup } from '@/hooks/usePopup' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilState, useRecoilValue } from 'recoil' import { fontSelector, globalFontAtom } from '@/store/fontAtom' -import { useFont } from '@/hooks/common/useFont' const fonts = [ { name: 'MS PGothic', value: 'MS PGothic' }, diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index 6b63f3d7..4cd63b1f 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -17,17 +17,31 @@ const TYPE = { LINE: 'LINE', } +const defaultDotLineGridSetting = { + INTERVAL: { + type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격 + ratioInterval: 910, + verticalInterval: 910, + horizontalInterval: 910, + dimension: 1, // 치수 + }, + DOT: false, + LINE: false, +} + export default function DotLineGrid(props) { // const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [close, setClose] = useState(false) const { id, setIsShow, pos = { x: 840, y: -815 } } = props const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) - const gridColor = useRecoilValue(gridColorState) + const canvas = useRecoilValue(canvasState) - const isGridDisplay = useRecoilValue(gridDisplaySelector) const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState) + const [currentSetting, setCurrentSetting] = useState( + JSON.stringify(dotLineGridSetting) === JSON.stringify(defaultDotLineGridSetting) ? { ...defaultDotLineGridSetting } : { ...dotLineGridSetting }, + ) const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState) const interval = useRecoilValue(dotLineIntervalSelector) @@ -70,7 +84,7 @@ export default function DotLineGrid(props) { const handleCheckBoxChange = (e) => { const { value, checked } = e.target - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, [value]: checked, @@ -101,160 +115,35 @@ export default function DotLineGrid(props) { setSelectOption(matchedOption) // 서버에서 받은 데이터로 상태 업데이트 - setDotLineGridSettingState(patternData) + setCurrentSetting(patternData) } catch (error) { console.error('Data fetching error:', error) } } const handleSave = async () => { - if (!dotLineGridSetting.DOT && !dotLineGridSetting.LINE) { + if (!currentSetting.DOT && !currentSetting.LINE) { swalFire({ text: '배치할 그리드를 설정해주세요.' }) return } try { const patternData = { objectNo, - dotGridDisplay: dotLineGridSetting.DOT, - lineGridDisplay: dotLineGridSetting.LINE, - gridType: dotLineGridSetting.INTERVAL.type, - gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval / 10, - gridVertical: dotLineGridSetting.INTERVAL.verticalInterval / 10, - gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, - gridDimen: dotLineGridSetting.INTERVAL.dimension, + dotGridDisplay: currentSetting.DOT, + lineGridDisplay: currentSetting.LINE, + gridType: currentSetting.INTERVAL.type, + gridHorizon: currentSetting.INTERVAL.horizontalInterval / 10, + gridVertical: currentSetting.INTERVAL.verticalInterval / 10, + gridRatio: currentSetting.INTERVAL.ratioInterval / 10, + gridDimen: currentSetting.INTERVAL.dimension, } // HTTP POST 요청 보내기 await post({ url: `/api/canvas-management/canvas-grid-settings`, data: patternData }).then((res) => { swalFire({ text: getMessage(res.returnMessage) }) - - // 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 (patternData.dotGridDisplay) { - 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: patternData.gridHorizon, - height: patternData.gridVertical, - }) - - 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', - visible: isGridDisplay, - }, - ) - - canvas.add(backgroundPolygon) - backgroundPolygon.sendToBack() - canvas.renderAll() - } - - if (patternData.lineGridDisplay) { - for (let i = 0; i < canvas.height / patternData.gridVertical + 1; i++) { - const horizontalLine = new fabric.Line( - [ - 0, - i * patternData.gridVertical - patternData.gridVertical / 2, - canvas.width, - i * patternData.gridVertical - patternData.gridVertical / 2, - ], - { - stroke: gridColor, - strokeWidth: 1, - selectable: true, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - name: 'lineGrid', - strokeDashArray: [5, 2], - opacity: 0.3, - direction: 'horizontal', - visible: isGridDisplay, - }, - ) - canvas.add(horizontalLine) - } - - for (let i = 0; i < canvas.width / patternData.gridHorizon + 1; i++) { - const verticalLine = new fabric.Line( - [ - i * patternData.gridHorizon - patternData.gridHorizon / 2, - 0, - i * patternData.gridHorizon - patternData.gridHorizon / 2, - canvas.height, - ], - { - stroke: gridColor, - strokeWidth: 1, - selectable: true, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - name: 'lineGrid', - strokeDashArray: [5, 2], - opacity: 0.3, - direction: 'vertical', - visible: isGridDisplay, - }, - ) - canvas.add(verticalLine) - } - } - - canvas.renderAll() + setDotLineGridSettingState({ ...currentSetting }) + closePopup(id) }) - setShowDotLineGridModal(false) - closePopup(id) } catch (error) { swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) } @@ -263,7 +152,7 @@ export default function DotLineGrid(props) { const handleRadioChange = (e) => { const { value, name, checked, selected } = e.target - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, INTERVAL: { @@ -276,7 +165,7 @@ export default function DotLineGrid(props) { const changeInput = (value, e) => { const { name } = e.target - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, INTERVAL: { @@ -289,7 +178,7 @@ export default function DotLineGrid(props) { const changeDimension = (result) => { const { value } = result - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, INTERVAL: { @@ -310,6 +199,7 @@ export default function DotLineGrid(props) { ?.getObjects() .filter((obj) => obj.name === 'dotGrid') .forEach((obj) => canvas?.remove(obj)) + resetDotLineGridSetting() setSelectOption(SelectOption[0]) } @@ -332,11 +222,11 @@ export default function DotLineGrid(props) {
- +
- +
@@ -349,8 +239,8 @@ export default function DotLineGrid(props) { id="ra01" value={1} onChange={handleRadioChange} - checked={(dotLineGridSetting.DOT || dotLineGridSetting.LINE) && dotLineGridSetting.INTERVAL.type === 1} - readOnly={!dotLineGridSetting.DOT && !dotLineGridSetting.LINE} + checked={(currentSetting.DOT || currentSetting.LINE) && currentSetting.INTERVAL.type === 1} + readOnly={!currentSetting.DOT && !currentSetting.LINE} />
@@ -361,7 +251,7 @@ export default function DotLineGrid(props) { type="text" className="input-origin" name={`horizontalInterval`} - value={dotLineGridSetting.INTERVAL.horizontalInterval} + value={currentSetting.INTERVAL.horizontalInterval} onChange={(e) => onlyNumberInputChange(e, changeInput)} /> @@ -374,7 +264,7 @@ export default function DotLineGrid(props) { type="text" className="input-origin" name={`verticalInterval`} - value={dotLineGridSetting.INTERVAL.verticalInterval} + value={currentSetting.INTERVAL.verticalInterval} onChange={(e) => onlyNumberInputChange(e, changeInput)} /> @@ -389,8 +279,8 @@ export default function DotLineGrid(props) { id="ra02" value={2} onChange={handleRadioChange} - checked={(dotLineGridSetting.DOT || dotLineGridSetting.LINE) && dotLineGridSetting.INTERVAL.type === 2} - readOnly={!dotLineGridSetting.DOT && !dotLineGridSetting.LINE} + checked={(currentSetting.DOT || currentSetting.LINE) && currentSetting.INTERVAL.type === 2} + readOnly={!currentSetting.DOT && !currentSetting.LINE} /> @@ -401,7 +291,7 @@ export default function DotLineGrid(props) { type="text" className="input-origin" name={`ratioInterval`} - value={dotLineGridSetting.INTERVAL.ratioInterval} + value={currentSetting.INTERVAL.ratioInterval} onChange={(e) => onlyNumberInputChange(e, changeInput)} /> diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js index 7421c53f..fd5d4542 100644 --- a/src/hooks/common/useCanvasConfigInitialize.js +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -1,12 +1,31 @@ -import { use, useEffect } from 'react' -import { useRecoilValue } from 'recoil' -import { settingModalFirstOptionsState } from '@/store/settingAtom' -import { canvasState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { roofDisplaySelector, settingModalFirstOptionsState } from '@/store/settingAtom' +import { canvasState, dotLineGridSettingState } from '@/store/canvasAtom' import { setSurfaceShapePattern } from '@/util/canvas-util' +import { useFont } from '@/hooks/common/useFont' +import { useGrid } from '@/hooks/common/useGrid' +import { globalFontAtom } from '@/store/fontAtom' export function useCanvasConfigInitialize() { const canvas = useRecoilValue(canvasState) - const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState) + const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + const roofDisplay = useRecoilValue(roofDisplaySelector) + const setGlobalFonts = useSetRecoilState(globalFontAtom) + const setDotLineGridSetting = useSetRecoilState(dotLineGridSettingState) + const {} = useFont() + const {} = useGrid() + + useEffect(() => { + if (!canvas) return + canvas + .getObjects() + .filter((polygon) => polygon.name === 'roof') + .forEach((polygon) => { + setSurfaceShapePattern(polygon, roofDisplay.column) + }) + canvas.renderAll() + }, [roofDisplay]) const canvasLoadInit = () => { roofInit() //화면표시 초기화 @@ -14,18 +33,32 @@ export function useCanvasConfigInitialize() { //치수표시, 화면표시, 글꼴등 초기화 const roofInit = () => { - if (canvas) { - const roofDisplay = settingModalFirstOptions.option2.filter((item) => item.selected) + setSettingModalFirstOptions((prev) => { + // ...prev에서 내부에 있는 option2 객체의 주소값도 다르게 만들어줘 + const option1 = prev.option1.map((option) => { + return { ...option } + }) + const option2 = prev.option2.map((option) => { + return { ...option } + }) + const dimensionDisplay = prev.dimensionDisplay.map((option) => { + return { ...option } + }) + return { ...prev, option1, option2, dimensionDisplay } + }) - canvas - .getObjects() - .filter((polygon) => polygon.name === 'roof') - .forEach((polygon) => { - setSurfaceShapePattern(polygon, roofDisplay[0].column) - }) + setDotLineGridSetting((prev) => { + return { ...prev } + }) - canvas.renderAll() - } + setGlobalFonts((prev) => { + const commonText = { ...prev.commonText } + const dimensionLineText = { ...prev.dimensionLineText } + const flowText = { ...prev.flowText } + const lengthText = { ...prev.lengthText } + const circuitNumberText = { ...prev.circuitNumberText } + return { commonText, dimensionLineText, flowText, lengthText, circuitNumberText } + }) } return { canvasLoadInit } diff --git a/src/hooks/common/useGrid.js b/src/hooks/common/useGrid.js new file mode 100644 index 00000000..0c6159dd --- /dev/null +++ b/src/hooks/common/useGrid.js @@ -0,0 +1,145 @@ +import { useRecoilValue } from 'recoil' +import { canvasState, dotLineGridSettingState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { gridColorState } from '@/store/gridAtom' +import { gridDisplaySelector } from '@/store/settingAtom' + +export function useGrid() { + const canvas = useRecoilValue(canvasState) + + const dotLineGridSetting = useRecoilValue(dotLineGridSettingState) + const gridColor = useRecoilValue(gridColorState) + const isGridDisplay = useRecoilValue(gridDisplaySelector) + + useEffect(() => { + if (!canvas) { + return + } + const patternData = { + dotGridDisplay: dotLineGridSetting.DOT, + lineGridDisplay: dotLineGridSetting.LINE, + gridType: dotLineGridSetting.INTERVAL.type, + gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval / 10, + gridVertical: dotLineGridSetting.INTERVAL.verticalInterval / 10, + gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, + gridDimen: dotLineGridSetting.INTERVAL.dimension, + } + + // 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 (patternData.dotGridDisplay) { + 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: patternData.gridHorizon, + height: patternData.gridVertical, + }) + + 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', + visible: isGridDisplay, + }, + ) + + canvas.add(backgroundPolygon) + backgroundPolygon.sendToBack() + canvas.renderAll() + } + + if (patternData.lineGridDisplay) { + for (let i = 0; i < canvas.height / patternData.gridVertical + 1; i++) { + const horizontalLine = new fabric.Line( + [0, i * patternData.gridVertical - patternData.gridVertical / 2, canvas.width, i * patternData.gridVertical - patternData.gridVertical / 2], + { + stroke: gridColor, + strokeWidth: 1, + selectable: true, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + name: 'lineGrid', + strokeDashArray: [5, 2], + opacity: 0.3, + direction: 'horizontal', + visible: isGridDisplay, + }, + ) + canvas.add(horizontalLine) + } + + for (let i = 0; i < canvas.width / patternData.gridHorizon + 1; i++) { + const verticalLine = new fabric.Line( + [i * patternData.gridHorizon - patternData.gridHorizon / 2, 0, i * patternData.gridHorizon - patternData.gridHorizon / 2, canvas.height], + { + stroke: gridColor, + strokeWidth: 1, + selectable: true, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + name: 'lineGrid', + strokeDashArray: [5, 2], + opacity: 0.3, + direction: 'vertical', + visible: isGridDisplay, + }, + ) + canvas.add(verticalLine) + } + } + + canvas.renderAll() + }, [dotLineGridSetting]) + + return {} +} diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 71e49408..71ec1549 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -5,20 +5,20 @@ import { getDirectionByPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import { isSamePoint } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' +import { fontSelector } from '@/store/fontAtom' export const usePolygon = () => { const canvas = useRecoilValue(canvasState) const isFlowDisplay = useRecoilValue(flowDisplaySelector) - const fontSize = useRecoilValue(fontSizeState) - const fontFamily = useRecoilValue(fontFamilyState) + const flowFontOptions = useRecoilValue(fontSelector('flowText')) + const lengthTextFontOptions = useRecoilValue(fontSelector('lengthText')) const addPolygon = (points, options) => { const polygon = new QPolygon(points, { ...options, + fontSize: lengthTextFontOptions.fontSize.value, fill: options.fill || 'transparent', stroke: options.stroke || '#000000', - fontSize: fontSize, - fontFamily: fontFamily, selectable: true, }) @@ -53,9 +53,8 @@ export const usePolygon = () => { const text = new fabric.Text(length.toString(), { left: midPoint.x, top: midPoint.y, - fontSize: fontSize, - fontFamily: fontFamily, parentId: polygon.id, + fontSize: lengthTextFontOptions.fontSize.value, minX: Math.min(start.x, end.x), maxX: Math.max(start.x, end.x), minY: Math.min(start.y, end.y), @@ -403,8 +402,10 @@ export const usePolygon = () => { const addTextByArrows = (arrows, txt, canvas) => { arrows.forEach((arrow, index) => { const text = new fabric.Text(`${txt}${index + 1} (${arrow.pitch}寸)`, { - fontSize: fontSize, - fill: 'black', + fontSize: flowFontOptions.fontSize.value, + fill: flowFontOptions.fontColor.value, + fontFamily: flowFontOptions.fontFamily.value, + fontWeight: flowFontOptions.fontWeight.value, originX: 'center', originY: 'center', name: 'flowText',