diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index ed2e837f..d7130911 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,7 +1,7 @@ 'use client' import { useCanvas } from '@/hooks/useCanvas' -import { useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useRef, useState } from 'react' import { v4 as uuidv4 } from 'uuid' import { useMode } from '@/hooks/useMode' import { Mode } from '@/common/common' @@ -21,7 +21,7 @@ import { } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { getCanvasState, insertCanvasState } from '@/lib/canvas' -import { calculateIntersection } from '@/util/canvas-util' +import { calculateIntersection, distanceBetweenPoints } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import ThumbnailList from './ui/ThumbnailLIst' import QContextMenu from './common/context-menu/QContextMenu' @@ -31,6 +31,7 @@ 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' export default function Roof2(props) { const { name, userId, email, isLoggedIn } = props @@ -571,6 +572,1001 @@ export default function Roof2(props) { canvas?.renderAll() } + const createTemplate1 = () => { + const length1 = prompt('1번') + const length2 = prompt('2번') + + 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, y: pointer.y - parseInt(length2) / 2 }, + { x: pointer.x - parseInt(length1) / 2, y: pointer.y + parseInt(length1) / 2 }, + { x: pointer.x + parseInt(length1) / 2, y: pointer.y + parseInt(length1) / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createPentagon2 = () => { + const a = 400 //Number(prompt('a')) + const b = 200 //Number(prompt('b')) + const c = 250 //Number(prompt('c')) + const d = 150 //Number(prompt('d')) + + const t = (c * (a - b)) / (200 + c) + + const t2 = Math.sqrt(c * c + t * t) + + const t3 = Math.sqrt((c - d) * (c - d) + (a - b - t) * (a - b - t)) + + 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) => { + if (!isDrawing) { + return + } + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) + const pointer = canvas?.getPointer(e.e) + + pentagon = new QPolygon( + [ + { x: pointer.x - a / 2, y: pointer.y + a / 2 - d }, + { x: pointer.x + a / 2, y: pointer.y + a / 2 - d }, + { x: pointer.x + a / 2, y: pointer.y + a / 2 - d - d }, + { x: pointer.x + a / 2 - b, y: pointer.y + a / 2 - d - d }, + { + x: pointer.x + a / 2 - b - t3 * Math.cos(angle), + y: pointer.y + a / 2 - d - d - t3 * Math.sin(angle), + }, + /*{ + x: pointer.x - a / 2 + t2 * Math.cos(angle), + y: pointer.y + a / 2 - d - t2 * Math.sin(angle), + },*/ + ], + { + 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() + }) + } + + const createTemplate2 = () => { + const length1 = prompt('1번') + const length2 = prompt('2번') + + 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 + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createTemplate3 = () => { + const length1 = Number(prompt('1번')) + const length2 = Number(prompt('2번')) + const length3 = Number(prompt('3번')) + + 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 + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length3 / 2, y: pointer.y - length2 / 2 }, + { x: pointer.x - length3 / 2, y: pointer.y - length2 / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createTemplate4 = () => { + const length1 = Number(prompt('1번')) + const length2 = Number(prompt('2번')) + + 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 + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createTemplate5 = () => { + const length1 = Number(prompt('1번')) + const length2 = Number(prompt('2번')) + + 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 + length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createTemplate6 = () => { + const length1 = Number(prompt('1번')) + const length2 = Number(prompt('2번')) + const length3 = Number(prompt('3번')) + + 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, y: pointer.y + length3 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 - length2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate7 = () => { + const length1 = Number(prompt('1번')) + const length2 = Number(prompt('2번')) + const length3 = Number(prompt('3번')) + + 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 - length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 - length3 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate8 = () => { + const length1 = Number(prompt('1번')) // 밑변 + const length2 = Number(prompt('2번')) // 높이 + const length3 = Number(prompt('3번')) // 빗변 + + const angleInRadians = Math.asin(length2 / length3) + + 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 + length2 / 2 }, + { x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate9 = () => { + const length1 = Number(prompt('1번')) // 밑변 + const length2 = Number(prompt('2번')) // 높이 + const length3 = Number(prompt('3번')) // 빗변 + + const angleInRadians = Math.asin(length2 / length3) + + 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 + length2 / 2 }, + { x: pointer.x + length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x - length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate10 = () => { + const length1 = Number(prompt('1번')) + const length2 = Number(prompt('2번')) + const length3 = Number(prompt('3번')) + const length4 = Number(prompt('4번')) + const length5 = Number(prompt('5번')) + + 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 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 }, + { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 }, + { + x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, + y: pointer.y + (length4 + length5) / 2 - length5 + length5, + }, + { + x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, + y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5), + }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate11 = () => { + const length1 = 200 //Number(prompt('1번')) + const length2 = 100 //Number(prompt('2번')) + const length3 = 400 //Number(prompt('3번')) + const length4 = 300 //Number(prompt('4번')) + + 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 + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 }, + { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 }, + { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, + { x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate12 = () => { + const length1 = 200 //Number(prompt('1번')) + const length2 = 100 //Number(prompt('2번')) + const length3 = 400 //Number(prompt('3번')) + const length4 = 300 //Number(prompt('4번')) + + 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 + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, + { x: pointer.x - length1 / 2 + length1 - length2 - (length1 - length2), y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate13 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 150 //Number(prompt('2번')) + const length3 = 100 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 200 //Number(prompt('5번')) + + 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 + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + { x: pointer.x - length1 / 2 + length1 - length3 - length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate14 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 150 //Number(prompt('2번')) + const length3 = 100 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 200 //Number(prompt('5번')) + + 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 + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + { x: pointer.x + length1 / 2 - length1 + length3 + length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate15 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 150 //Number(prompt('2번')) + const length3 = 100 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 200 //Number(prompt('5번')) + + 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 + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate16 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 150 //Number(prompt('2번')) + const length3 = 100 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 200 //Number(prompt('5번')) + + 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 + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate17 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 150 //Number(prompt('2번')) + const length3 = 250 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 200 //Number(prompt('5번')) + + 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 + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate18 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 150 //Number(prompt('2번')) + const length3 = 250 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 200 //Number(prompt('5번')) + + 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 + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + /** + * 19~22번은 못함 + */ + const createTemplate23 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 100 //Number(prompt('2번')) + const length3 = 150 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('4번')) + const length5 = 300 //Number(prompt('5번')) + + 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 + length2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 }, + { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 }, + { x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, y: pointer.y + length4 / 2 - length4 + length5 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createTemplate24 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 400 //Number(prompt('2번')) + const length3 = 300 //Number(prompt('3번')) + + 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 + length2 - length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, + { x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate25 = () => { + const length1 = 300 //Number(prompt('1번')) + const length2 = 200 //Number(prompt('2번')) + const length3 = 300 //Number(prompt('3번')) + const length4 = 200 //Number(prompt('3번')) + + 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 - length2) / 2, + y: pointer.y + length3 / 2 - (length3 - length4), + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2, + y: pointer.y + length3 / 2 - (length3 - length4) - length4, + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, + y: pointer.y + length3 / 2 - (length3 - length4) - length4, + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, + y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4, + }, + { + x: pointer.x - length1 / 2 + length1, + y: pointer.y + length3 / 2, + }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate26 = () => { + //todo + const length1 = 300 //Number(prompt('1번')) + const length2 = 200 //Number(prompt('2번')) + const length3 = 300 //Number(prompt('3번')) + const length4 = 400 //Number(prompt('3번')) + + 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([], { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }) + + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + const createTemplate28 = () => { + 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 + b) / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, + { + x: pointer.x + length1 / 2 - b / 2 + d * Math.cos(newAngleInRadians), + y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians), + }, + { + x: pointer.x - (length1 + b) / 2 + length3 * Math.cos(newAngleInRadians), + y: pointer.y + length2 / 2 - length3 * 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 ( <> {canvas && ( @@ -717,6 +1713,78 @@ export default function Roof2(props) { + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/fabric/HelpLine.js b/src/components/fabric/HelpLine.js deleted file mode 100644 index 68112099..00000000 --- a/src/components/fabric/HelpLine.js +++ /dev/null @@ -1,108 +0,0 @@ -import { fabric } from 'fabric' - -export class QLine extends fabric.Group { - line - text - fontSize - length = 0 - x1 - y1 - x2 - y2 - direction - type = 'HelpLine' - parent - #lengthTxt = 0 - - constructor(points, option, lengthTxt) { - const [x1, y1, x2, y2] = points - - if (!option.fontSize) { - throw new Error('Font size is required.') - } - - const line = new fabric.Line(points, { ...option, strokeWidth: 1 }) - super([line], {}) - - this.x1 = x1 - this.y1 = y1 - this.x2 = x2 - this.y2 = y2 - this.line = line - this.fontSize = option.fontSize - this.direction = option.direction - this.parent = option.parent - - if (lengthTxt > 0) { - this.#lengthTxt = Number(lengthTxt) - } - - this.#init() - this.#addControl() - } - - #init() { - this.#addLengthText(true) - } - - #addControl() { - this.on('moving', () => { - this.#addLengthText(false) - }) - - this.on('modified', (e) => { - this.#addLengthText(false) - }) - - this.on('selected', () => { - Object.keys(this.controls).forEach((controlKey) => { - if (controlKey !== 'ml' && controlKey !== 'mr') { - this.setControlVisible(controlKey, false) - } - }) - }) - } - - #addLengthText(isFirst) { - if (this.text) { - this.removeWithUpdate(this.text) - this.text = null - } - - if (isFirst && this.#lengthTxt > 0) { - const text = new fabric.Textbox(this.#lengthTxt.toFixed(0).toString(), { - left: (this.x1 + this.x2) / 2, - top: (this.y1 + this.y2) / 2, - fontSize: this.fontSize, - }) - this.length = this.#lengthTxt - this.text = text - this.addWithUpdate(text) - return - } - - const scaleX = this.scaleX - const scaleY = this.scaleY - const x1 = this.left - const y1 = this.top - const x2 = this.left + this.width * scaleX - const y2 = this.top + this.height * scaleY - const dx = x2 - x1 - const dy = y2 - y1 - this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) - - const text = new fabric.Textbox(this.length.toFixed(0).toString(), { - left: (x1 + x2) / 2, - top: (y1 + y2) / 2, - fontSize: this.fontSize, - }) - this.text = text - this.addWithUpdate(text) - } - - setFontSize(fontSize) { - this.fontSize = fontSize - this.text.set({ fontSize }) - this.addWithUpdate() - } -} diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index c5093f91..c6da782f 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -18,6 +18,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { parentId: null, innerLines: [], children: [], + initOptions: null, initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { @@ -58,6 +59,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.canvas = canvas } + this.initOptions = options + this.init() this.initLines() this.setShape() @@ -177,7 +180,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const degree = (Math.atan2(dy, dx) * 180) / Math.PI // Create new text object if it doesn't exist - const text = new fabric.Text(length.toFixed(0), { + const text = new fabric.IText(length.toFixed(0), { left: midPoint.x, top: midPoint.y, fontSize: this.fontSize, @@ -189,7 +192,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { parentDirection: getDirectionByPoint(start, end), parentDegree: degree, dirty: true, - editable: false, + editable: true, selectable: true, lockRotation: true, lockScalingX: true, diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index ee2f2fdd..e5582733 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -2,6 +2,7 @@ import { useEffect, useState } from 'react' import { fabric } from 'fabric' import { useRecoilState, useRecoilValue } from 'recoil' import { canvasSizeState, currentObjectState, modeState } from '@/store/canvasAtom' +import { QPolygon } from '@/components/fabric/QPolygon' // 캔버스에 필요한 이벤트 export function useCanvasEvent() { @@ -77,11 +78,55 @@ export function useCanvasEvent() { if (target.name === 'lengthText') { const x = target.left const y = target.top + // Add a property to store the previous value + const previousValue = target.text target.on('selected', (e) => { Object.keys(target.controls).forEach((controlKey) => { target.setControlVisible(controlKey, false) }) }) + target.on('editing:exited', () => { + if (isNaN(target.text.trim())) { + target.set({ text: previousValue }) + canvas?.renderAll() + return + } + const updatedValue = parseFloat(target.text.trim()) + const targetParent = target.parent + const points = targetParent.getCurrentPoints() + const i = target.idx // Assuming target.index gives the index of the point + + const startPoint = points[i] + const endPoint = points[(i + 1) % points.length] + + const dx = endPoint.x - startPoint.x + const dy = endPoint.y - startPoint.y + + const currentLength = Math.sqrt(dx * dx + dy * dy) + const scaleFactor = updatedValue / currentLength + + const newEndPoint = { + x: startPoint.x + dx * scaleFactor, + y: startPoint.y + dy * scaleFactor, + } + + const newPoints = [...points] + newPoints[(i + 1) % points.length] = newEndPoint + + for (let idx = i + 1; idx < points.length; idx++) { + if (newPoints[idx].x === endPoint.x) { + newPoints[idx].x = newEndPoint.x + } else if (newPoints[idx].y === endPoint.y) { + newPoints[idx].y = newEndPoint.y + } + } + + const newPolygon = new QPolygon(newPoints, targetParent.initOptions) + canvas?.add(newPolygon) + canvas?.remove(targetParent) + canvas?.renderAll() + }) + target.on('moving', (e) => { if (target.parentDirection === 'left' || target.parentDirection === 'right') { const minX = target.minX @@ -116,7 +161,6 @@ export function useCanvasEvent() { if (whiteList.includes(e.target.name)) { return } - console.log('removed', e) }, } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 4d6dc238..b6c4680d 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -101,6 +101,8 @@ export function useMode() { }, [endPoint]) useEffect(() => { + canvas?.off('mouse:out', removeMouseLines) + canvas?.on('mouse:out', removeMouseLines) changeMode(canvas, mode) canvas?.off('mouse:move') canvas?.on('mouse:move', drawMouseLines) @@ -160,6 +162,53 @@ export function useMode() { if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) { let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null if ((horiGuideLines.length > 0 || vertGuideLines.length > 0) && guideDotMode) { + const closestHorizontalLine = getClosestHorizontalLine(pointer, horiGuideLines) + const closetVerticalLine = getClosestVerticalLine(pointer, vertGuideLines) + let intersection = null + let intersectionDistance = Infinity + + if (closestHorizontalLine && closetVerticalLine) { + intersection = calculateIntersection(closestHorizontalLine, closetVerticalLine) + if (intersection) { + intersectionDistance = distanceBetweenPoints(pointer, intersection) + } + } + + let xDiff, yDiff + + if (closetVerticalLine) { + xDiff = Math.abs(pointer.x - closetVerticalLine.x1) + } + if (closestHorizontalLine) { + yDiff = Math.abs(pointer.y - closestHorizontalLine.y1) + } + + const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) + const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert) + + const xRate = x / guideLineLengthHori + const yRate = y / guideLineLengthVert + const isAttachX = xRate >= 0.4 && xRate <= 0.7 + const isAttachY = yRate >= 0.4 && yRate <= 0.7 + if (isAttachX && isAttachY) { + newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2 + newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2 + } else { + if (intersection && intersectionDistance < 20) { + newX = intersection.x + newY = intersection.y + } else { + if (Math.min(xDiff, yDiff) <= 20) { + if (xDiff < yDiff) { + newX = closetVerticalLine.x1 + newY = pointer.y + } else { + newX = pointer.x + newY = closestHorizontalLine.y1 + } + } + } + } } else if (guideDotMode) { const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori) const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)