2024-10-18 13:36:32 +09:00

1001 lines
30 KiB
JavaScript

'use client'
import { useCanvas } from '@/hooks/useCanvas'
import { useEffect, useRef, useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMode } from '@/hooks/useMode'
import { Mode } from '@/common/common'
import { Button, Input } from '@nextui-org/react'
import RangeSlider from './ui/RangeSlider'
import { useRecoilState, useRecoilValue } from 'recoil'
import {
cadFileCompleteState,
cadFileNameState,
canvasSizeState,
compassState,
currentObjectState,
fontSizeState,
globalCompassState,
googleMapFileNameState,
roofMaterialState,
roofState,
sortedPolygonArray,
templateTypeState,
useCadFileState,
useGoogleMapFileState,
wallState,
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
import { calculateIntersection } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon'
import QContextMenu from './common/context-menu/QContextMenu'
import { modalContent, modalState } from '@/store/modalAtom'
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 InitSettingsModal from './InitSettingsModal'
import GridSettingsModal from './GridSettingsModal'
import { SurfaceShapeModal } from '@/components/ui/SurfaceShape'
import { drawDirectionStringToArrow } from '@/util/qpolygon-utils'
import ThumbnailList from '@/components/ui/ThumbnailLIst'
import ObjectPlacement from '@/components/ui/ObjectPlacement'
import { globalLocaleStore } from '@/store/localeAtom'
export default function Roof2(props) {
const { name, userId, email, isLoggedIn } = props
const {
canvas,
handleRedo,
handleUndo,
setCanvasBackgroundWithDots,
saveImage,
addCanvas,
handleBackImageLoadToCanvas,
handleCadImageInit,
backImg,
setBackImg,
} = useCanvas('canvas')
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get } = useAxios(globalLocaleState)
const canvasRef = useRef(null)
//canvas 기본 사이즈
const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
//canvas 가로 사이즈
const [verticalSize, setVerticalSize] = useState(canvasSize.vertical)
//canvas 세로 사이즈
const [horizontalSize, setHorizontalSize] = useState(canvasSize.horizontal)
// 글자크기
const [fontSize, setFontSize] = useRecoilState(fontSizeState)
const [sortedArray] = useRecoilState(sortedPolygonArray)
const [angle, setAngle] = useState(0)
const [showControl, setShowControl] = useState(false)
//지붕재
const roofMaterial = useRecoilValue(roofMaterialState)
const [templateType, setTemplateType] = useRecoilState(templateTypeState)
const [compass, setCompass] = useRecoilState(compassState)
const roof = useRecoilValue(roofState)
const wall = useRecoilValue(wallState)
const [open, setOpen] = useRecoilState(modalState)
const [contents, setContent] = useRecoilState(modalContent)
const [scale, setScale] = useState(1)
const currentObject = useRecoilValue(currentObjectState)
//canvas 썸네일
const [thumbnails, setThumbnails] = useState([])
const thumbnailProps = {
thumbnails,
canvas,
}
let imgPath
// cad 파일 업로드
const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState)
const [cadFileComplete, setCadFileComplete] = useRecoilState(cadFileCompleteState)
useCadFile && (imgPath = `/cadImages/${cadFileName}`)
// 구글맵 이미지 업로드
const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState)
const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState)
useGoogleMapFile && (imgPath = `/mapImages/${googleMapFileName}`)
const [globalCampass, setGlobalCampass] = useRecoilState(globalCompassState)
const {
mode,
setMode,
changeMode,
handleClear,
zoomIn,
zoomOut,
zoom,
togglePolygonLine,
handleOuterlinesTest,
handleOuterlinesTest2,
applyTemplateB,
makeRoofPatternPolygon,
createRoofRack,
drawRoofPolygon,
drawCellInTrestle,
drawCellManualInTrestle,
setDirectionTrestles,
cutHelpLines,
} = useMode()
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
useEffect(() => {
get({ url: `/api/canvas-management/canvas-statuses/by-object/test123240822001/${userId}` }).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, '')
const test2 = test.substring(1, test.length - 1)
return {
id: item.id,
userId: item.userId,
imageName: `/canvasState/${item.imageName}.png`,
canvasStatus: JSON.stringify(test2),
}
})
setThumbnails(arrangeData)
})
}, [])
useEffect(() => {
if (!canvas) {
return
}
changeMode(canvas, mode)
if (!cadFileComplete && useCadFile) {
// cad 파일 로드
useCadFile && handleBackImageLoadToCanvas(imgPath, canvas)
}
if (useGoogleMapFile) {
handleBackImageLoadToCanvas(imgPath, canvas)
}
}, [canvas, mode])
const makeLine = () => {
if (canvas) {
const line = new QLine([50, 50, 200, 50], {
stroke: 'black',
selectable: true,
strokeWidth: 2,
fontSize: fontSize,
})
canvas?.add(line)
}
}
const makePolygon = () => {
if (canvas) {
const polygon = new QPolygon(
[
{ x: 100, y: 100 },
{ x: 600, y: 200 },
{ x: 700, y: 800 },
{ x: 100, y: 800 },
],
{
fill: 'transparent',
stroke: 'black',
strokeWidth: 2,
selectable: true,
fontSize: fontSize,
},
)
canvas?.add(polygon)
// polygon.fillCell({ width: 50, height: 30, padding: 10 })
}
}
useEffect(() => {
setCanvasSize({ ...canvasSize, vertical: parseInt(verticalSize), horizontal: parseInt(horizontalSize) })
}, [verticalSize, horizontalSize])
/**
* 값 변경시
*/
// useEffect(() => {
// canvasSizeMode()
// }, [verticalSize, horizontalSize])
useEffect(() => {
const { vertical, horizontal } = canvasSize
if (vertical !== verticalSize || horizontal !== horizontalSize) {
canvas?.setWidth(horizontalSize)
canvas?.setHeight(verticalSize)
canvas?.renderAll()
}
}, [canvasSize, canvas])
const makeQPolygon = () => {
const type1 = [
{ x: 100, y: 100 },
{ x: 850, y: 100 },
{ x: 850, y: 800 },
{ x: 500, y: 800 },
{ x: 500, y: 400 },
{ x: 100, y: 400 },
]
const type2 = [
{ x: 200, y: 100 },
{ x: 200, y: 1000 },
{ x: 1100, y: 1000 },
{ x: 1100, y: 600 },
{ x: 650, y: 600 },
{ x: 650, y: 100 },
]
const type3 = [
{ x: 200, y: 100 },
{ x: 200, y: 800 },
{ x: 500, y: 800 },
{ x: 500, y: 300 },
{ x: 800, y: 300 },
{ x: 800, y: 100 },
]
const type4 = [
{ x: 150, y: 450 },
{ x: 150, y: 800 },
{ x: 750, y: 800 },
{ x: 750, y: 300 },
{ x: 550, y: 300 },
{ x: 550, y: 450 },
]
const type1A = [
{ x: 67, y: 81 },
{ x: 67, y: 660 },
{ x: 437, y: 660 },
{ x: 437, y: 1190 },
{ x: 858, y: 1190 },
{ x: 858, y: 81 },
]
const type1B = [
{ x: 137, y: 42 },
{ x: 137, y: 621 },
{ x: 667, y: 621 },
{ x: 667, y: 991 },
{ x: 1088, y: 991 },
{ x: 1088, y: 42 },
]
const eightPoint = [
{ x: 240.1111, y: 130.1111 },
{ x: 240.1111, y: 630.1111 },
{ x: 640.1111, y: 630.1111 },
{ x: 640.1111, y: 480.1111 },
{ x: 440.1111, y: 480.1111 },
{ x: 440.1111, y: 280.1111 },
{ x: 740.1111, y: 280.1111 },
{ x: 740.1111, y: 130.1111 },
]
const eightPoint2 = [
{ x: 197, y: 215 },
{ x: 197, y: 815 },
{ x: 397, y: 815 },
{ x: 397, y: 1115 },
{ x: 697, y: 1115 },
{ x: 697, y: 815 },
{ x: 897, y: 815 },
{ x: 897, y: 215 },
]
const eightPoint3 = [
{ x: 190, y: 147 },
{ x: 190, y: 747 },
{ x: 490, y: 747 },
{ x: 490, y: 497 },
{ x: 640, y: 497 },
{ x: 640, y: 747 },
{ x: 1090, y: 747 },
{ x: 1090, y: 147 },
]
const eightPoint4 = [
{ x: 200, y: 200 },
{ x: 200, y: 400 },
{ x: 500, y: 400 },
{ x: 500, y: 700 },
{ x: 800, y: 700 },
{ x: 800, y: 400 },
{ x: 1100, y: 400 },
{ x: 1100, y: 200 },
]
const eightPoint5 = [
{ x: 140, y: 101 },
{ x: 140, y: 601 },
{ x: 440, y: 601 },
{ x: 440, y: 801 },
{ x: 840, y: 801 },
{ x: 840, y: 601 },
{ x: 1140, y: 601 },
{ x: 1140, y: 101 },
]
const twelvePoint = [
{ x: 195, y: 166 },
{ x: 195, y: 466 },
{ x: 395, y: 466 },
{ x: 395, y: 766 },
{ x: 545, y: 766 },
{ x: 545, y: 466 },
{ x: 695, y: 466 },
{ x: 695, y: 666 },
{ x: 845, y: 666 },
{ x: 845, y: 466 },
{ x: 995, y: 466 },
{ x: 995, y: 166 },
]
const twelvePoint2 = [
{ x: 165, y: 81 },
{ x: 165, y: 1081 },
{ x: 465, y: 1081 },
{ x: 465, y: 781 },
{ x: 765, y: 781 },
{ x: 765, y: 1081 },
{ x: 1065, y: 1081 },
{ x: 1065, y: 581 },
{ x: 765, y: 581 },
{ x: 765, y: 281 },
{ x: 1065, y: 281 },
{ x: 1065, y: 81 },
]
const complicatedType = [
{ x: 100, y: 100 },
{ x: 100, y: 1100 },
{ x: 400, y: 1100 },
{ x: 400, y: 800 },
{ x: 700, y: 800 },
{ x: 700, y: 1100 },
{ x: 1000, y: 1100 },
{ x: 1000, y: 600 },
{ x: 700, y: 600 },
{ x: 700, y: 300 },
{ x: 1000, y: 300 },
{ x: 1000, y: 100 },
]
const testType = [
{ x: 500, y: 400 },
{ x: 650, y: 550 },
{ x: 575, y: 625 },
{ x: 325, y: 625 },
{ x: 100, y: 400 },
]
const testType2 = [
{ x: 100, y: 400 },
{ x: 325, y: 625 },
{ x: 575, y: 625 },
{ x: 650, y: 550 },
{ x: 500, y: 400 },
]
const triangleType = [
{ x: 100, y: 100 },
{ x: 100, y: 600 },
{ x: 600, y: 600 },
{ x: 600, y: 100 },
]
const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint]
const newP = [
{ x: 450, y: 450 },
{ x: 650, y: 250 },
{ x: 675, y: 275 },
{ x: 450, y: 850 },
]
const polygon = new QPolygon(twelvePoint, {
fill: 'transparent',
stroke: 'green',
strokeWidth: 1,
selectable: false,
fontSize: fontSize,
name: 'wall',
})
canvas?.add(polygon)
handleOuterlinesTest2(polygon, 50)
setTemplateType(1)
}
const rotateShape = () => {
if (canvas) {
const activeObject = canvas?.getActiveObject()
if (activeObject) {
activeObject.rotate(angle)
canvas?.renderAll()
}
}
}
const makeQLine = () => {
if (canvas) {
const line = new QLine([50, 250, 900, 250], {
stroke: 'black',
strokeWidth: 5,
fontSize: fontSize,
selectable: true,
})
const line2 = new QLine([450, 450, 821, 78], {
stroke: 'black',
strokeWidth: 5,
fontSize: fontSize,
selectable: true,
})
canvas?.add(line)
canvas?.add(line2)
const interSectionPoint = calculateIntersection(line, line2)
if (interSectionPoint) {
const circle = new fabric.Circle({
radius: 5,
fill: 'red',
left: interSectionPoint.x - 5,
top: interSectionPoint.y - 5,
})
canvas?.add(circle)
}
}
}
const addBackgroundInPolygon = (polygon) => {
fabric.Image.fromURL('assets/img/check2.png', function (img) {
// 패턴 객체를 생성합니다.
const pattern = new fabric.Pattern({
source: img.getElement(),
repeat: 'repeat',
})
polygon.fillBackground(pattern)
})
}
function PolygonToLine() {
const polygon = canvas?.getActiveObject()
if (polygon.type !== 'QPolygon') {
return
}
const lines = togglePolygonLine(polygon)
}
/**
* canvas 내용 저장하기
*/
const handleSaveCanvas = async () => {
// const jsonStr = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize']))
const jsonObj = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize', 'lines']))
console.log(jsonObj)
const param = {
loginId: 'test',
canvas: jsonObj,
}
console.log(param)
await insertCanvasState(param)
handleClear()
}
const drawRoofMaterial = () => {
const { width, height, roofStyle } = roofMaterial
const wallPolygon = canvas?.getObjects().find((obj) => obj.name === 'wall')
wallPolygon.set('strokeDashArray', [10, 5, 2, 5])
wallPolygon.set('stroke', 'blue')
wallPolygon.set('strokeWidth', 1)
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
roofs.forEach((roof) => {
let maxLengthLine = roof.lines.reduce((acc, cur) => {
return acc.length > cur.length ? acc : cur
})
const roofRatio = window.devicePixelRatio || 1
// 패턴 소스를 위한 임시 캔버스 생성
const patternSourceCanvas = document.createElement('canvas')
if (roofStyle === 1) {
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
patternSourceCanvas.width = width * roofRatio
patternSourceCanvas.height = height * roofRatio
} else {
patternSourceCanvas.width = height * roofRatio
patternSourceCanvas.height = width * roofRatio
}
} else if (roofStyle === 2) {
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
patternSourceCanvas.width = width * 2
patternSourceCanvas.height = height * 2
} else {
patternSourceCanvas.width = height * 2
patternSourceCanvas.height = width * 2
}
}
const ctx = patternSourceCanvas.getContext('2d')
ctx.scale(roofRatio, roofRatio)
ctx.strokeStyle = 'green'
ctx.lineWidth = 0.4
// 벽돌 패턴 그리기
if (roofStyle === 1) {
ctx.strokeRect(0, 0, 50, 30)
} else if (roofStyle === 2) {
// 지그재그
ctx.strokeRect(0, 0, 200, 100)
ctx.strokeRect(100, 100, 200, 100)
}
// 패턴 생성
const pattern = new fabric.Pattern({
source: patternSourceCanvas,
repeat: 'repeat',
})
roof.set('fill', null)
roof.set('fill', pattern)
canvas?.renderAll()
})
}
/**
* canvas 내용 불러오기
*/
const handleLoadCanvas = async () => {
const canvasStates = await getCanvasState()
console.log(JSON.parse(canvasStates.canvas))
canvas?.loadFromJSON(JSON.parse(canvasStates.canvas))
}
/**
* 컨트롤러 보이기/숨기기
*/
const handleShowController = () => {
setShowControl(!showControl)
}
const drawRoofPatterns = (roofStyle) => {
makeRoofPatternPolygon(roofStyle)
}
const deleteCell = () => {
const selectedCells = canvas?.getObjects().filter((obj) => obj.name === 'cell' && obj.selected)
selectedCells.forEach((cell) => {
canvas?.remove(cell)
})
}
const setCompassState = (degree) => {
setCompass(degree)
}
const changeLength = (e) => {
const polygon = canvas?.getActiveObject()
if (polygon?.type !== 'QPolygon') {
return
}
setScale(e)
polygon.setScaleX(e)
canvas?.renderAll()
}
const moduleConfiguration = () => {
createRoofRack()
}
const setDirectionStringToArrow = () => {
drawDirectionStringToArrow(canvas, globalCampass)
/**
* 나중에 유틸로 다시 구현
*/
// const groupShapes = canvas?.getObjects().filter((obj) => obj.name === 'cellGroup')
// console.log('groupShapes', groupShapes)
// groupShapes.forEach((obj) => {
// let originAngle = obj._objects.find((array) => array.originAngle !== undefined).originAngle
// console.log('originAngle', originAngle)
// let rotateAngle = globalCampass
// // let rotateAngle = originAngle + globalCampass
// // if (rotateAngle > 360) {
// // rotateAngle -= 360
// // }
// console.log('rotateAngle', rotateAngle)
// obj.set({ angle: rotateAngle, originX: 'center', originY: 'center' })
// obj.setCoords()
// })
canvas?.renderAll()
}
const setAllGableRoof = () => {
let offset = Number(prompt('gable roof offset', '50'))
if (!isNaN(offset) && offset > 0) {
const polygon = canvas?.getObjects()
console.log('gable roof offset : ', offset)
console.log('polygon : ', polygon)
changeAllGableRoof(polygon, offset, canvas)
} else {
alert('offset 은 0 보다 커야 함')
}
}
return (
<>
{canvas && (
<>
<div className=" my-8 w-full text:pretty">
<Button
className="m-1 p-2"
onClick={() => {
setContent(<InitSettingsModal canvasProps={canvas} />)
setOpen(true)
}}
>
배치면 초기설정
</Button>
<Button
className="m-1 p-2"
onClick={() => {
setContent(<GridSettingsModal canvasProps={canvas} />)
setOpen(true)
}}
>
그리드 설정
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.DEFAULT ? 'primary' : 'default'}`} onClick={() => setMode(Mode.DEFAULT)}>
모드 DEFAULT
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.DRAW_LINE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.DRAW_LINE)}>
임의 그리드 모드
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.EDIT ? 'primary' : 'default'}`} onClick={() => setMode(Mode.EDIT)}>
에디팅모드
</Button>
<Button
className="m-1 p-2"
color={`${mode === Mode.MOUSE_DISTANCE ? 'primary' : 'default'}`}
onClick={() => setMode(Mode.MOUSE_DISTANCE)}
>
마우스거리 모드
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.TEMPLATE)}>
템플릿(기둥)
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.PATTERNA)}>
템플릿(A 패턴)
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.PATTERNB)}>
템플릿(B 패턴)
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => drawRoofPatterns(1)}>
지붕패턴1
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => drawRoofPatterns(2)}>
지붕패턴2
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setCompassState(90)}>
방위표
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setCompassState(270)}>
방위표
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setCompassState(180)}>
방위표
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setCompassState(0)}>
방위표
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.ROOF_TRESTLE)}>
지붕가대생성
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.FILL_CELLS)}>
태양광셀생성
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => setMode(Mode.CELL_POWERCON)}>
파워콘설치
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => setMode(Mode.TEXTBOX)}>
텍스트박스 모드
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.DRAW_RECT ? 'primary' : 'default'}`} onClick={() => setMode(Mode.DRAW_RECT)}>
도머 추가 모드
</Button>
<Button
className="m-1 p-2"
color={`${mode === Mode.ADSORPTION_POINT ? 'primary' : 'default'}`}
onClick={() => setMode(Mode.ADSORPTION_POINT)}
>
흡착점 모드
</Button>
<Button
className="m-1 p-2"
color={`${mode === Mode.DRAW_HELP_LINE ? 'primary' : 'default'}`}
onClick={() => setMode(Mode.DRAW_HELP_LINE)}
>
보조선 연결 모드
</Button>
<Button className="m-1 p-2" onClick={handleUndo}>
Undo
</Button>
<Button className="m-1 p-2" onClick={handleRedo}>
Redo
</Button>
<Button className="m-1 p-2" onClick={handleClear}>
clear
</Button>
{
<Button className="m-1 p-2" onClick={zoomIn}>
확대
</Button>
}
<Button className="m-1 p-2" onClick={zoomOut}>
축소
</Button>
현재 : {zoom}%
<Button className="m-1 p-2" onClick={makeLine}>
추가
</Button>
<Button className="m-1 p-2" onClick={makePolygon}>
다각형 추가
</Button>
{templateType === 0 && (
<>
<Button className="m-1 p-2" onClick={makeQPolygon}>
QPolygon
</Button>
</>
)}
<Button className={'m-1 p-2'} onClick={setAllGableRoof}>
팔작지붕
</Button>
<Button className="m-1 p-2" onClick={() => saveImage(uuidv4(), userId, setThumbnails)}>
저장
</Button>
<Button
className="m-1 p-2"
onClick={() => {
setContent(<SurfaceShapeModal canvas={canvas} />)
setOpen(true)
}}
>
면형상
</Button>
<Button
className="m-1 p-2"
onClick={() => {
setContent(<ObjectPlacement canvas={canvas} />)
setOpen(true)
}}
>
오브젝트 배치
</Button>
{/*<Button className="m-1 p-2" onClick={rotateShape}>
회전
</Button>*/}
{/*<Button className="m-1 p-2" onClick={makeQLine}>
QLine
</Button>
<Button className="m-1 p-2" onClick={PolygonToLine}>
PolygonToLine
</Button>
<Button className="m-1 p-2" onClick={addCanvas}>
캔버스 추가
</Button>*/}
<Button className="m-1 p-2" onClick={cutHelpLines}>
보조선 절삭
</Button>
{templateType === 1 && (
<>
<Button className="m-1 p-2" onClick={drawRoofMaterial}>
지붕타입 지붕재
</Button>
<Button className="m-1 p-2" onClick={createRoofRack}>
지붕가대설치
</Button>
<Button className="m-1 p-2" onClick={setDirectionTrestles}>
가대 방향 설정
</Button>
<Button className="m-1 p-2" onClick={drawCellInTrestle}>
선택한 가대 셀채우기
</Button>
</>
)}
<Button className="m-1 p-2" onClick={deleteCell}>
선택 지우기
</Button>
<Button className="m-1 p-2" onClick={moduleConfiguration}>
모듈,회로구성
</Button>
<Button className="m-1 p-2" onClick={drawCellInTrestle}>
모듈 채우기
</Button>
<Button className="m-1 p-2" onClick={drawCellManualInTrestle}>
수동 모듈 채우기
</Button>
<Button
className="m-1 p-2"
onClick={() => {
if (useCadFile) {
setUseCadFile(false)
setCadFileName('')
handleCadImageInit()
}
}}
>
cad 파일 초기화
</Button>
<Button
className="m-1 p-2"
onClick={() => {
if (useCadFile) {
backImg
.set({
selectable: false,
opacity: 0.7,
})
.sendToBack()
canvas.clear()
canvas.add(backImg)
canvas.renderAll()
setCadFileComplete(true)
}
}}
>
배경 이미지 조정 완료
</Button>
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
</Button>
</div>
<div className={showControl ? `flex justify-center flex-col items-center` : `hidden`}>
<div className="m-2 p-2 w-80">
<RangeSlider title={`각도${angle}`} initValue={angle} min="0" step="1" max="360" onchange={setAngle} />
</div>
<div className="m-2 p-2 w-80">
<RangeSlider
title={`canvas 가로 사이즈${horizontalSize}`}
initValue={horizontalSize}
min="500"
step="100"
max="2000"
onchange={setHorizontalSize}
/>
</div>
<div className="m-2 p-2 w-80">
<RangeSlider
title={`canvas 세로 사이즈${verticalSize}`}
initValue={verticalSize}
min="500"
step="100"
max="2000"
onchange={setVerticalSize}
/>
</div>
<div className="m-2 p-2 w-80">
<RangeSlider title={`글자 크기${fontSize}`} initValue={fontSize} onchange={setFontSize} />
</div>
<div className="m-2 p-2 w-80">
<RangeSlider title={`선택한 obj 가로 늘리기${scale}`} initValue={scale} min={0.01} max={2.0} step={0.01} onchange={changeLength} />
</div>
</div>
</>
)}
<ThumbnailList {...thumbnailProps} />
<div className={'flex'}>
<p className={'m-1 p-3'}>각도 입력(0~360) 방향설정 클릭</p>
<Input
className="m-1 p-3"
type={'text'}
value={globalCampass}
onChange={(e) => {
const val = e.target.value.replace(/[^-0-9]/g, '')
if (val < 0 || val > 360) {
setGlobalCampass(0)
} else {
setGlobalCampass(Number(val))
}
}}
/>
<Button className="m-1 p-3" onClick={setDirectionStringToArrow}>
방향 설정
</Button>
</div>
<div className="relative w-48 h-48 flex justify-center items-center border-2 border-gray-300 rounded-full">
{/* Compass Circle */}
<div
className="absolute w-full h-full border-2 border-gray-300 rounded-full flex justify-center items-center"
style={{ rotate: `${globalCampass}deg` }}
>
{/* N, S, E, W Labels */}
<div className="absolute top-2 text-lg font-bold">N</div>
<div className="absolute bottom-2 text-lg font-bold">S</div>
<div className="absolute right-2 text-lg font-bold" style={{ rotate: '90deg' }}>
E
</div>
<div className="absolute left-2 text-lg font-bold" style={{ rotate: '-90deg' }}>
W
</div>
</div>
{/* Compass Pointer */}
<div className="relative w-10 h-10">
{/* Red Upper Triangle */}
<div
className="absolute top-0"
style={{
width: 0,
height: 0,
rotate: `${globalCampass - 180}deg`,
borderLeft: '15px solid transparent',
borderRight: '15px solid transparent',
borderTop: '60px solid red',
}}
/>
</div>
</div>
<div className="flex justify-start my-8 mx-2 w-full">
<canvas ref={canvasRef} id="canvas" style={{ border: '1px solid black' }} />
{!canvas ? null : mode === Mode.DRAW_LINE ? (
<QEmptyContextMenu contextRef={canvasRef} canvasProps={canvas} />
) : currentObject?.type === 'QPolygon' ? (
<QPolygonContextMenu contextRef={canvasRef} canvasProps={canvas} />
) : currentObject?.type === 'QLine' ? (
<QLineContextMenu contextRef={canvasRef} canvasProps={canvas} />
) : (
<QContextMenu contextRef={canvasRef} canvasProps={canvas} />
)}
</div>
</>
)
}