494 lines
13 KiB
JavaScript
494 lines
13 KiB
JavaScript
import { useCanvas } from '@/hooks/useCanvas'
|
|
import { useEffect, useState } from 'react'
|
|
import { Mode, useMode } from '@/hooks/useMode'
|
|
import { Button } from '@nextui-org/react'
|
|
import QRect from '@/components/fabric/QRect'
|
|
import QPolygon from '@/components/fabric/QPolygon'
|
|
|
|
import RangeSlider from './ui/RangeSlider'
|
|
import { useRecoilState } from 'recoil'
|
|
import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
|
|
import { QLine } from '@/components/fabric/QLine'
|
|
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
|
import { calculateIntersection2 } from '@/util/canvas-util'
|
|
|
|
export default function Roof2() {
|
|
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
|
|
|
//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 {
|
|
mode,
|
|
changeMode,
|
|
handleClear,
|
|
fillCellInPolygon,
|
|
zoomIn,
|
|
zoomOut,
|
|
zoom,
|
|
togglePolygonLine,
|
|
handleOuterlinesTest,
|
|
handleOuterlinesTest2,
|
|
applyTemplateB,
|
|
makeRoofPatternPolygon,
|
|
} = useMode()
|
|
|
|
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
|
|
|
|
useEffect(() => {
|
|
if (!canvas) {
|
|
return
|
|
}
|
|
changeMode(canvas, mode)
|
|
}, [canvas, mode])
|
|
|
|
const makeRect = () => {
|
|
if (canvas) {
|
|
const rect = new QRect({
|
|
left: 100,
|
|
top: 100,
|
|
fill: 'transparent',
|
|
stroke: 'black',
|
|
width: 400,
|
|
height: 100,
|
|
fontSize: fontSize,
|
|
})
|
|
|
|
canvas?.add(rect)
|
|
}
|
|
}
|
|
|
|
const makeLine = () => {
|
|
if (canvas) {
|
|
const line = new QLine([50, 50, 200, 50], {
|
|
stroke: 'black',
|
|
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,
|
|
)
|
|
|
|
canvas?.add(polygon)
|
|
|
|
polygon.fillCell({ width: 50, height: 30, padding: 10 })
|
|
}
|
|
}
|
|
|
|
/**
|
|
* canvas 사이즈 변경 함수
|
|
*/
|
|
const canvasSizeMode = () => {
|
|
if (canvas) {
|
|
canvas.setWidth(horizontalSize)
|
|
canvas.setHeight(verticalSize)
|
|
canvas.renderAll()
|
|
|
|
setCanvasSize(() => ({
|
|
vertical: verticalSize,
|
|
horizontal: horizontalSize,
|
|
}))
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 값 변경시
|
|
*/
|
|
useEffect(() => {
|
|
canvasSizeMode()
|
|
}, [verticalSize, horizontalSize])
|
|
|
|
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: 100, y: 100 },
|
|
{ x: 100, y: 1000 },
|
|
{ x: 1000, y: 1000 },
|
|
{ x: 1000, y: 600 },
|
|
{ x: 550, y: 600 },
|
|
{ x: 550, 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, y: 130 },
|
|
{ x: 240, y: 630 },
|
|
{ x: 640, y: 630 },
|
|
{ x: 640, y: 480 },
|
|
{ x: 440, y: 480 },
|
|
{ x: 440, y: 280 },
|
|
{ x: 740, y: 280 },
|
|
{ x: 740, y: 130 },
|
|
]
|
|
|
|
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 },
|
|
]
|
|
|
|
if (canvas) {
|
|
const polygon = new QPolygon(eightPoint, {
|
|
fill: 'transparent',
|
|
stroke: 'black',
|
|
strokeWidth: 1,
|
|
selectable: true,
|
|
fontSize: fontSize,
|
|
name: 'QPolygon1',
|
|
})
|
|
|
|
canvas?.add(polygon)
|
|
|
|
console.log(polygon)
|
|
|
|
handleOuterlinesTest2(polygon)
|
|
|
|
// const lines = togglePolygonLine(polygon)
|
|
// togglePolygonLine(lines[0])
|
|
}
|
|
}
|
|
|
|
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,
|
|
},
|
|
50,
|
|
)
|
|
|
|
const line2 = new QLine(
|
|
[450, 450, 821, 78],
|
|
{
|
|
stroke: 'black',
|
|
strokeWidth: 5,
|
|
fontSize: fontSize,
|
|
selectable: true,
|
|
},
|
|
50,
|
|
)
|
|
|
|
canvas?.add(line)
|
|
canvas?.add(line2)
|
|
|
|
const interSectionPoint = calculateIntersection2(line, line2)
|
|
|
|
if (interSectionPoint) {
|
|
console.log(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()
|
|
}
|
|
|
|
/**
|
|
* 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)
|
|
}
|
|
|
|
return (
|
|
<>
|
|
{canvas && (
|
|
<>
|
|
<div className=" my-8 w-full text:pretty">
|
|
<Button className="m-1 p-2" color={`${mode === Mode.DEFAULT ? 'primary' : 'default'}`} onClick={fillCellInPolygon}>
|
|
모드 DEFAULT
|
|
</Button>
|
|
<Button
|
|
className="m-1 p-2"
|
|
color={`${mode === Mode.DRAW_LINE ? 'primary' : 'default'}`}
|
|
onClick={() => changeMode(canvas, Mode.DRAW_LINE)}
|
|
>
|
|
기준선 긋기 모드
|
|
</Button>
|
|
<Button className="m-1 p-2" color={`${mode === Mode.EDIT ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.EDIT)}>
|
|
에디팅모드
|
|
</Button>
|
|
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEMPLATE)}>
|
|
템플릿(기둥)
|
|
</Button>
|
|
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.PATTERNA)}>
|
|
템플릿(A 패턴)
|
|
</Button>
|
|
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, 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.TEXTBOX ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEXTBOX)}>
|
|
텍스트박스 모드
|
|
</Button>
|
|
<Button
|
|
className="m-1 p-2"
|
|
color={`${mode === Mode.DRAW_RECT ? 'primary' : 'default'}`}
|
|
onClick={() => changeMode(canvas, Mode.DRAW_RECT)}
|
|
>
|
|
사각형 생성 모드
|
|
</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={makeRect}>
|
|
사각형만들기
|
|
</Button>
|
|
<Button className="m-1 p-2" onClick={makeLine}>
|
|
선 추가
|
|
</Button>
|
|
<Button className="m-1 p-2" onClick={makePolygon}>
|
|
다각형 추가
|
|
</Button>
|
|
<Button
|
|
className="m-1 p-2"
|
|
onClick={() => {
|
|
setCanvasBackgroundWithDots(canvas, 10)
|
|
}}
|
|
>
|
|
점선 추가
|
|
</Button>
|
|
<Button
|
|
className="m-1 p-2"
|
|
onClick={() => {
|
|
setCanvasBackgroundWithDots(canvas, 20)
|
|
}}
|
|
>
|
|
점선 추가
|
|
</Button>
|
|
<Button className="m-1 p-2" onClick={saveImage}>
|
|
저장
|
|
</Button>
|
|
<Button className="m-1 p-2" onClick={makeQPolygon}>
|
|
QPolygon
|
|
</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={handleSaveCanvas}>
|
|
canvas 내용 저장하기
|
|
</Button>
|
|
<Button className="m-1 p-2" onClick={handleLoadCanvas}>
|
|
canvas 내용 불러오기
|
|
</Button>*/}
|
|
<Button className="m-1 p-2" onClick={addCanvas}>
|
|
캔버스 추가
|
|
</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>
|
|
</>
|
|
)}
|
|
<div className="flex justify-start my-8 mx-2 w-full">
|
|
<canvas id="canvas" style={{ border: '1px solid black' }} />
|
|
</div>
|
|
</>
|
|
)
|
|
}
|