813 lines
24 KiB
JavaScript
813 lines
24 KiB
JavaScript
'use client'
|
|
|
|
import { useCanvas } from '@/hooks/useCanvas'
|
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { useMode } from '@/hooks/useMode'
|
|
import { Mode } from '@/common/common'
|
|
import { Button } from '@nextui-org/react'
|
|
import RangeSlider from './ui/RangeSlider'
|
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
|
import {
|
|
canvasSizeState,
|
|
compassState,
|
|
currentObjectState,
|
|
fontSizeState,
|
|
roofMaterialState,
|
|
roofState,
|
|
sortedPolygonArray,
|
|
templateTypeState,
|
|
wallState,
|
|
} from '@/store/canvasAtom'
|
|
import { QLine } from '@/components/fabric/QLine'
|
|
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
|
import { calculateIntersection, distanceBetweenPoints, getIntersectionPoint } from '@/util/canvas-util'
|
|
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 { 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 { degreesToRadians, point, radiansToDegrees } from '@turf/turf'
|
|
|
|
import InitSettingsModal from './InitSettingsModal'
|
|
import GridSettingsModal from './GridSettingsModal'
|
|
import { SurfaceShapeModal } from '@/components/ui/SurfaceShape'
|
|
|
|
export default function Roof2(props) {
|
|
const { name, userId, email, isLoggedIn } = props
|
|
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
|
|
|
const { get } = useAxios()
|
|
|
|
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,
|
|
}
|
|
|
|
const {
|
|
mode,
|
|
setMode,
|
|
changeMode,
|
|
handleClear,
|
|
zoomIn,
|
|
zoomOut,
|
|
zoom,
|
|
togglePolygonLine,
|
|
handleOuterlinesTest,
|
|
handleOuterlinesTest2,
|
|
applyTemplateB,
|
|
makeRoofPatternPolygon,
|
|
createRoofRack,
|
|
drawRoofPolygon,
|
|
drawCellInTrestle,
|
|
setDirectionTrestles,
|
|
cutHelpLines,
|
|
} = useMode()
|
|
|
|
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
|
|
|
|
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, '')
|
|
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)
|
|
}, [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) => {
|
|
setScale(e)
|
|
const polygon = canvas?.getActiveObject()
|
|
if (polygon.type !== 'QPolygon') {
|
|
return
|
|
}
|
|
|
|
canvas?.renderAll()
|
|
}
|
|
|
|
const moduleConfiguration = () => {
|
|
createRoofRack()
|
|
}
|
|
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={() => 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={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" 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 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>
|
|
</>
|
|
)
|
|
}
|