diff --git a/package.json b/package.json index a6b4f511..bbd8c881 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "postcss": "^8", "prettier": "^3.3.3", "prisma": "^5.18.0", + "react-color-palette": "^7.2.2", "sass": "^1.77.8", "tailwindcss": "^3.4.1" } diff --git a/public/drawTemplates/153302.svg b/public/drawTemplates/153302.svg new file mode 100644 index 00000000..3b1c97b0 --- /dev/null +++ b/public/drawTemplates/153302.svg @@ -0,0 +1,23 @@ + + + + +Created by potrace 1.15, written by Peter Selinger 2001-2017 + + + + + + + diff --git a/public/drawTemplates/shape21.svg b/public/drawTemplates/shape21.svg new file mode 100644 index 00000000..a2d901e7 --- /dev/null +++ b/public/drawTemplates/shape21.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/SettingsModal.jsx b/src/components/GridSettingsModal.jsx similarity index 87% rename from src/components/SettingsModal.jsx rename to src/components/GridSettingsModal.jsx index dc7dc5ba..35bb1793 100644 --- a/src/components/SettingsModal.jsx +++ b/src/components/GridSettingsModal.jsx @@ -4,8 +4,10 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { modalContent, modalState } from '@/store/modalAtom' import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom' import { fabric } from 'fabric' +import { ColorPicker, useColor } from 'react-color-palette' +import 'react-color-palette/css' -export default function SettingsModal(props) { +export default function GridSettingsModal(props) { const { canvasProps } = props const [isCustomGridSetting, setIsCustomGridSetting] = useState(true) const [gridCheckedValue, setGridCheckValue] = useState([]) @@ -21,6 +23,15 @@ export default function SettingsModal(props) { const gridSettingArray = [] + const [guideColor, setGuideColor] = useColor('rgb(200, 15, 15)') + const [colorPickerShow, setColorPickerShow] = useState(false) + + const boxStyle = { + width: '50px', + height: '30px', + border: '1px solid black', + backgroundColor: guideColor.hex, + } useEffect(() => { moduleLength.current.value = 90 customModuleHoriLength.current.value = 90 @@ -56,7 +67,7 @@ export default function SettingsModal(props) { const horizontalLine = new fabric.Line( [0, i * moduleVertLength - moduleVertLength / 2, canvasProps.width, i * moduleVertLength - moduleVertLength / 2], { - stroke: 'gray', + stroke: guideColor.hex, strokeWidth: 1, selectable: true, lockMovementX: true, @@ -65,6 +76,8 @@ export default function SettingsModal(props) { lockScalingX: true, lockScalingY: true, name: 'guideLine', + strokeDashArray: [5, 2], + opacity: 0.3, direction: 'horizontal', }, ) @@ -76,7 +89,7 @@ export default function SettingsModal(props) { const verticalLine = new fabric.Line( [i * moduleHoriLength - moduleHoriLength / 2, 0, i * moduleHoriLength - moduleHoriLength / 2, canvasProps.height], { - stroke: 'gray', + stroke: guideColor.hex, strokeWidth: 1, selectable: true, lockMovementX: true, @@ -85,6 +98,8 @@ export default function SettingsModal(props) { lockScalingX: true, lockScalingY: true, name: 'guideLine', + strokeDashArray: [5, 2], + opacity: 0.3, direction: 'vertical', }, ) @@ -118,7 +133,9 @@ export default function SettingsModal(props) { if (gridCheckedValue.includes('dot')) { const circle = new fabric.Circle({ radius: 2, - fill: 'red', + fill: 'white', + stroke: guideColor.hex, + strokeWidth: 0.7, originX: 'center', originY: 'center', selectable: false, @@ -216,10 +233,18 @@ export default function SettingsModal(props) { 임의간격 -
- - 종횡연동 - +
+ 가이드컬러
setColorPickerShow(!colorPickerShow)}>
+
+ {colorPickerShow && ( + + )} + +
+ + 종횡연동 + +
@@ -229,6 +254,7 @@ export default function SettingsModal(props) { mm
+
+ ※ 지붕재는 최대 4종까지 선택할 수 있습니다. +
+ + {basicSetting.roofs && + basicSetting.roofs.map((roof, index) => { + return + })} + +
+ + +
+ + + ) +} + +const RoofSelectBox = (props) => { + return ( +
+ + props.onChange(props.roof.id, e)} + /> + props.onChange(props.roof.id, e)} + /> + mm + props.onChange(props.roof.id, e)} /> + mm +
+ props.onChange(props.roof.id, e)} + > + 병렬식 + 계단식 + +
+
+ ) +} diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index d7130911..af96faa9 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -26,12 +26,14 @@ import { QPolygon } from '@/components/fabric/QPolygon' import ThumbnailList from './ui/ThumbnailLIst' import QContextMenu from './common/context-menu/QContextMenu' import { modalContent, modalState } from '@/store/modalAtom' -import SettingsModal from './SettingsModal' import { useAxios } from '@/hooks/useAxios' import QPolygonContextMenu from '@/components/common/context-menu/QPolygonContextMenu' import QLineContextMenu from '@/components/common/context-menu/QLineContextMenu' import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMenu' -import { radiansToDegrees } from '@turf/turf' +import { degreesToRadians, radiansToDegrees } from '@turf/turf' + +import InitSettingsModal from './InitSettingsModal' +import GridSettingsModal from './GridSettingsModal' export default function Roof2(props) { const { name, userId, email, isLoggedIn } = props @@ -105,6 +107,8 @@ export default function Roof2(props) { useEffect(() => { get({ url: `/api/canvas-management/canvas-statuses/by-object/test123240822001` }).then((res) => { + console.log(res) + const arrangeData = res.map((item) => { console.log(item.canvasStatus.replace(/##/g, '"').replace(/\\/g, '')) const test = item.canvasStatus.replace(/##/g, '"').replace(/\\/g, '') @@ -622,8 +626,6 @@ export default function Roof2(props) { const angle = Math.atan(t2 / t) const angle2 = Math.atan(t3 / (a - b - t)) - console.log(angle, angle2) - let isDrawing = true let pentagon canvas?.on('mouse:move', (e) => { @@ -1466,12 +1468,15 @@ export default function Roof2(props) { }) } const createTemplate26 = () => { - //todo - const length1 = 300 //Number(prompt('1번')) + const length1 = 500 //Number(prompt('1번')) const length2 = 200 //Number(prompt('2번')) const length3 = 300 //Number(prompt('3번')) const length4 = 400 //Number(prompt('3번')) + const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 + + const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 + let isDrawing = true canvas?.on('mouse:move', (e) => { if (!isDrawing) { @@ -1479,14 +1484,95 @@ export default function Roof2(props) { } canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon([], { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }) + const triangle = new QPolygon( + [ + { + x: pointer.x - length1 / 2 + length1, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2, + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), + }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate27 = () => { + const length1 = 500 //Number(prompt('1번')) + const length2 = 200 //Number(prompt('2번')) + const length3 = 300 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('3번')) + + const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 + + const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 + + let isDrawing = true + canvas?.on('mouse:move', (e) => { + if (!isDrawing) { + return + } + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) + const pointer = canvas?.getPointer(e.e) + const triangle = new QPolygon( + [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + length1, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2, + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2 - topL * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), + }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) canvas?.add(triangle) }) @@ -1566,6 +1652,74 @@ export default function Roof2(props) { canvas?.renderAll() }) } + const createTemplate29 = () => { + const length1 = Number(prompt('밑변')) + const length2 = Number(prompt('높이')) + const length3 = Number(prompt('빗변')) + + const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 + + const sinA = a / length3 + const angleInRadians = Math.asin(sinA) + const angleInDegrees = angleInRadians * (180 / Math.PI) + const b = a - length1 / 2 + + const c = b / Math.tan(angleInRadians) + const d = Math.sqrt(b * b + c * c) + + if (isNaN(a)) { + alert('값이 잘못되었습니다.') + return + } + if (b < 0) { + alert('값이 잘못되었습니다.') + return + } + if (angleInDegrees === 0 || angleInRadians === 0) { + alert('값이 잘못되었습니다.') + return + } + + let isDrawing = true + let pentagon + canvas?.on('mouse:move', (e) => { + if (!isDrawing) { + return + } + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) + const pointer = canvas?.getPointer(e.e) + const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) + + pentagon = new QPolygon( + [ + { + x: pointer.x + length1 / 2 - b / 2 - length3 * Math.cos(newAngleInRadians), + y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), + }, + { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - (length1 + b) / 2 - d * Math.cos(newAngleInRadians), y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians) }, + ], + { + fill: 'transparent', + stroke: 'gray', + strokeWidth: 1, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(pentagon) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + pentagon.set('name', 'roof') + pentagon.set('stroke', 2) + canvas?.renderAll() + }) + } return ( <> @@ -1575,7 +1729,24 @@ export default function Roof2(props) { + + + + diff --git a/src/components/ui/ThumbnailLIst.jsx b/src/components/ui/ThumbnailLIst.jsx index b50f506f..1d67dbe8 100644 --- a/src/components/ui/ThumbnailLIst.jsx +++ b/src/components/ui/ThumbnailLIst.jsx @@ -19,7 +19,7 @@ function ThumbnailList(props) {
{thumbnails.length > 0 && thumbnails.map((thumbnail, index) => ( - +