Merge branch 'feature/test' of https://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into feature/test

This commit is contained in:
hyojun.choi 2024-07-18 12:52:48 +09:00
commit 7cd40816f1
5 changed files with 176 additions and 205 deletions

View File

@ -4,7 +4,7 @@
"useTabs": false, "useTabs": false,
"tabWidth": 2, "tabWidth": 2,
"trailingComma": "all", "trailingComma": "all",
"printWidth": 80, "printWidth": 150,
"arrowParens": "always", "arrowParens": "always",
"endOfLine": "auto" "endOfLine": "auto"
} }

View File

@ -1,6 +1,5 @@
'use client' 'use client'
import Hero from '@/components/Hero'
import Roof2 from '@/components/Roof2' import Roof2 from '@/components/Roof2'
import { textState } from '@/store/canvasAtom' import { textState } from '@/store/canvasAtom'
import { useEffect } from 'react' import { useEffect } from 'react'

View File

@ -7,21 +7,11 @@ import QPolygon from '@/components/fabric/QPolygon'
import RangeSlider from './ui/RangeSlider' import RangeSlider from './ui/RangeSlider'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
canvasSizeState,
fontSizeState,
sortedPolygonArray,
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
export default function Roof2() { export default function Roof2() {
const { const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage } = useCanvas('canvas')
canvas,
handleRedo,
handleUndo,
setCanvasBackgroundWithDots,
saveImage,
} = useCanvas('canvas')
//canvas //canvas
const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState) const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
@ -39,18 +29,8 @@ export default function Roof2() {
const [showControl, setShowControl] = useState(false) const [showControl, setShowControl] = useState(false)
const { const { mode, changeMode, handleClear, fillCellInPolygon, zoomIn, zoomOut, zoom, togglePolygonLine, handleOuterlinesTest2, applyTemplateB } =
mode, useMode()
changeMode,
handleClear,
fillCellInPolygon,
zoomIn,
zoomOut,
zoom,
togglePolygonLine,
handleOuterlinesTest2,
applyTemplateB,
} = useMode()
useEffect(() => { useEffect(() => {
if (!canvas) { if (!canvas) {
@ -265,11 +245,7 @@ export default function Roof2() {
{canvas && ( {canvas && (
<> <>
<div className=" my-8 w-full text:pretty"> <div className=" my-8 w-full text:pretty">
<Button <Button className="m-1 p-2" color={`${mode === Mode.DEFAULT ? 'primary' : 'default'}`} onClick={fillCellInPolygon}>
className="m-1 p-2"
color={`${mode === Mode.DEFAULT ? 'primary' : 'default'}`}
onClick={fillCellInPolygon}
>
모드 DEFAULT 모드 DEFAULT
</Button> </Button>
<Button <Button
@ -279,39 +255,19 @@ export default function Roof2() {
> >
기준선 긋기 모드 기준선 긋기 모드
</Button> </Button>
<Button <Button className="m-1 p-2" color={`${mode === Mode.EDIT ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.EDIT)}>
className="m-1 p-2"
color={`${mode === Mode.EDIT ? 'primary' : 'default'}`}
onClick={() => changeMode(canvas, Mode.EDIT)}
>
에디팅모드 에디팅모드
</Button> </Button>
<Button <Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEMPLATE)}>
className="m-1 p-2"
color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`}
onClick={() => changeMode(canvas, Mode.TEMPLATE)}
>
템플릿(기둥) 템플릿(기둥)
</Button> </Button>
<Button <Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.PATTERNA)}>
className="m-1 p-2"
color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`}
onClick={() => {}}
>
템플릿(A 패턴) 템플릿(A 패턴)
</Button> </Button>
<Button <Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.PATTERNB)}>
className="m-1 p-2"
color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`}
onClick={applyTemplateB}
>
템플릿(B 패턴) 템플릿(B 패턴)
</Button> </Button>
<Button <Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEXTBOX)}>
className="m-1 p-2"
color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`}
onClick={() => changeMode(canvas, Mode.TEXTBOX)}
>
텍스트박스 모드 텍스트박스 모드
</Button> </Button>
<Button <Button
@ -377,30 +333,13 @@ export default function Roof2() {
<Button className="m-1 p-2" onClick={PolygonToLine}> <Button className="m-1 p-2" onClick={PolygonToLine}>
PolygonToLine PolygonToLine
</Button> </Button>
<Button <Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
className="m-1 p-2"
color={`${showControl ? 'primary' : 'default'}`}
onClick={handleShowController}
>
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`} canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
</Button> </Button>
</div> </div>
<div <div className={showControl ? `flex justify-center flex-col items-center` : `hidden`}>
className={
showControl
? `flex justify-center flex-col items-center`
: `hidden`
}
>
<div className="m-2 p-2 w-80"> <div className="m-2 p-2 w-80">
<RangeSlider <RangeSlider title={`각도${angle}`} initValue={angle} min="0" step="1" max="360" onchange={setAngle} />
title={`각도${angle}`}
initValue={angle}
min="0"
step="1"
max="360"
onchange={setAngle}
/>
</div> </div>
<div className="m-2 p-2 w-80"> <div className="m-2 p-2 w-80">
<RangeSlider <RangeSlider
@ -423,11 +362,7 @@ export default function Roof2() {
/> />
</div> </div>
<div className="m-2 p-2 w-80"> <div className="m-2 p-2 w-80">
<RangeSlider <RangeSlider title={`글자 크기${fontSize}`} initValue={fontSize} onchange={setFontSize} />
title={`글자 크기${fontSize}`}
initValue={fontSize}
onchange={setFontSize}
/>
</div> </div>
</div> </div>
</> </>

View File

@ -15,7 +15,7 @@ export class QLine extends fabric.Group {
parent parent
#lengthTxt = 0 #lengthTxt = 0
constructor(points, option, lengthTxt) { constructor(points, option = { isActiveLengthText: true }, lengthTxt) {
const [x1, y1, x2, y2] = points const [x1, y1, x2, y2] = points
if (!option.fontSize) { if (!option.fontSize) {
@ -39,7 +39,7 @@ export class QLine extends fabric.Group {
this.#lengthTxt = Number(lengthTxt) this.#lengthTxt = Number(lengthTxt)
} }
this.#init() option.isActiveLengthText ?? this.#init()
this.#addControl() this.#addControl()
} }

View File

@ -1,28 +1,17 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import QRect from '@/components/fabric/QRect' import QRect from '@/components/fabric/QRect'
import QPolygon from '@/components/fabric/QPolygon' import QPolygon from '@/components/fabric/QPolygon'
import { import { getStartIndex, rearrangeArray, findTopTwoIndexesByDistance, getDirection, getCenterPoint } from '@/util/canvas-util'
getStartIndex,
rearrangeArray,
findTopTwoIndexesByDistance,
getDirection,
getOddEvenPoints,
findLongestDistancePair,
getCenterPoint,
} from '@/util/canvas-util'
import { useRecoilState, useSetRecoilState } from 'recoil' import { useRecoilState, useSetRecoilState } from 'recoil'
import { import { fontSizeState, roofState, sortedPolygonArray, wallState } from '@/store/canvasAtom'
fontSizeState,
roofState,
sortedPolygonArray,
wallState,
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
export const Mode = { export const Mode = {
DRAW_LINE: 'drawLine', // 기준선 긋기모드 DRAW_LINE: 'drawLine', // 기준선 긋기모드
EDIT: 'edit', EDIT: 'edit',
TEMPLATE: 'template', TEMPLATE: 'template',
PATTERNA: 'patterna',
PATTERNB: 'patternb',
TEXTBOX: 'textbox', TEXTBOX: 'textbox',
DRAW_RECT: 'drawRect', DRAW_RECT: 'drawRect',
DEFAULT: 'default', DEFAULT: 'default',
@ -55,6 +44,11 @@ export function useMode() {
case 'template': case 'template':
templateMode() templateMode()
break break
case 'patterna':
break
case 'patternb':
applyTemplateB()
break
case 'textbox': case 'textbox':
textboxMode() textboxMode()
break break
@ -96,8 +90,7 @@ export function useMode() {
if (isNaN(length) || length === 0) { if (isNaN(length) || length === 0) {
//마지막 추가 된 points 제거합니다. //마지막 추가 된 points 제거합니다.
const lastPoint = const lastPoint = historyPoints.current[historyPoints.current.length - 1]
historyPoints.current[historyPoints.current.length - 1]
canvas?.remove(lastPoint) canvas?.remove(lastPoint)
@ -129,12 +122,7 @@ export function useMode() {
} }
const line = new QLine( const line = new QLine(
[ [points.current[0].left, points.current[0].top, points.current[0].left + scaledVector.x, points.current[0].top + scaledVector.y],
points.current[0].left,
points.current[0].top,
points.current[0].left + scaledVector.x,
points.current[0].top + scaledVector.y,
],
{ {
stroke: 'black', stroke: 'black',
strokeWidth: 2, strokeWidth: 2,
@ -175,27 +163,20 @@ export function useMode() {
} }
const pushHistoryLine = (line) => { const pushHistoryLine = (line) => {
if ( if (historyLines.current.length > 0 && historyLines.current[historyLines.current.length - 1].direction === line.direction) {
historyLines.current.length > 0 &&
historyLines.current[historyLines.current.length - 1].direction ===
line.direction
) {
// 같은 방향의 선이 두 번 연속으로 그려지면 이전 선을 제거하고, 새로운 선과 merge한다. // 같은 방향의 선이 두 번 연속으로 그려지면 이전 선을 제거하고, 새로운 선과 merge한다.
const lastLine = historyLines.current.pop() const lastLine = historyLines.current.pop()
canvas?.remove(lastLine) canvas?.remove(lastLine)
const mergedLine = new QLine( const mergedLine = new QLine([lastLine.x1, lastLine.y1, line.x2, line.y2], {
[lastLine.x1, lastLine.y1, line.x2, line.y2], stroke: 'black',
{ strokeWidth: 2,
stroke: 'black', selectable: false,
strokeWidth: 2, viewLengthText: true,
selectable: false, direction: lastLine.direction,
viewLengthText: true, fontSize: fontSize,
direction: lastLine.direction, })
fontSize: fontSize,
},
)
historyLines.current.push(mergedLine) historyLines.current.push(mergedLine)
canvas?.add(mergedLine) canvas?.add(mergedLine)
} else { } else {
@ -458,9 +439,7 @@ export function useMode() {
const newOuterlines = [] const newOuterlines = []
for (let i = 0; i < historyLines.current.length; i++) { for (let i = 0; i < historyLines.current.length; i++) {
const next = historyLines.current[i + 1] const next = historyLines.current[i + 1]
const prev = const prev = historyLines.current[i - 1] ?? historyLines.current[historyLines.current.length - 1]
historyLines.current[i - 1] ??
historyLines.current[historyLines.current.length - 1]
if (next) { if (next) {
if (next.direction === 'right') { if (next.direction === 'right') {
// 다름 라인이 오른쪽으로 이동 // 다름 라인이 오른쪽으로 이동
@ -795,9 +774,7 @@ export function useMode() {
} }
// 평균 법선 벡터를 단위 벡터로 정규화 // 평균 법선 벡터를 단위 벡터로 정규화
var lengthNormal = Math.sqrt( var lengthNormal = Math.sqrt(averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y)
averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y,
)
var unitNormal = { var unitNormal = {
x: averageNormal.x / lengthNormal, x: averageNormal.x / lengthNormal,
y: averageNormal.y / lengthNormal, y: averageNormal.y / lengthNormal,
@ -866,9 +843,7 @@ export function useMode() {
} }
// 평균 법선 벡터를 단위 벡터로 정규화 // 평균 법선 벡터를 단위 벡터로 정규화
const lengthNormal = Math.sqrt( const lengthNormal = Math.sqrt(averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y)
averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y,
)
const unitNormal = { const unitNormal = {
x: averageNormal.x / lengthNormal, x: averageNormal.x / lengthNormal,
y: averageNormal.y / lengthNormal, y: averageNormal.y / lengthNormal,
@ -933,64 +908,144 @@ export function useMode() {
const applyTemplateB = () => { const applyTemplateB = () => {
changeMode(canvas, Mode.EDIT) changeMode(canvas, Mode.EDIT)
const polygon = drawWallPolygon() const polygon = drawWallPolygon()
handleOuterLineTemplateB(polygon) console.log('polygon', polygon)
const params = {
eaves: 50,
edge: 20,
polygon,
}
handleInnerLineColor(polygon)
handleOuterLineTemplateB(params)
} }
const handleOuterLineTemplateB = (polygon) => { const handleInnerLineColor = (polygon) => {
polygon.lines.forEach((line, index) => {
if (index % 2 === 0) {
line.set('stroke', 'rgb(0, 220, 221)')
} else {
line.set('stroke', 'rgb(0, 224, 61)')
}
const overLine = new QLine([line.x1, line.y1, line.x2, line.y2], {
stroke: line.stroke,
strokeWidth: 2,
selectable: false,
fontSize: fontSize,
})
canvas.add(overLine)
})
canvas.renderAll()
}
const handleOuterLineTemplateB = (params) => {
const { eaves, edge, polygon } = params
polygon.points.forEach((point, index) => { polygon.points.forEach((point, index) => {
let x2 = let x2 = index === polygon.points.length - 1 ? polygon.points[0].x : polygon.points[index + 1].x
index === polygon.points.length - 1 let y2 = index === polygon.points.length - 1 ? polygon.points[0].y : polygon.points[index + 1].y
? polygon.points[0].x
: polygon.points[index + 1].x
let y2 =
index === polygon.points.length - 1
? polygon.points[0].y
: polygon.points[index + 1].y
let x1 = point.x let x1 = point.x
let y1 = point.y let y1 = point.y
if (index % 2 === 0) { if (index % 2 === 0) {
if (polygon.lines[index].direction === 'bottom') { if (polygon.lines[index].direction === 'bottom') {
y1 = y1 - 50 y1 = y1 - eaves
y2 = y2 + 50 y2 = y2 + eaves
x1 = x1 - 20 x1 = x1 - edge
x2 = x2 - 20 x2 = x2 - edge
} else { } else {
y1 = y1 + 50 y1 = y1 + eaves
y2 = y2 - 50 y2 = y2 - eaves
x1 = x1 + 20 x1 = x1 + edge
x2 = x2 + 20 x2 = x2 + edge
} }
} else { } else {
if (polygon.lines[index].direction === 'right') { if (polygon.lines[index].direction === 'right') {
x1 = x1 - 20 x1 = x1 - edge
x2 = x2 + 20 x2 = x2 + edge
y1 = y1 + 50 y1 = y1 + eaves
y2 = y2 + 50 y2 = y2 + eaves
} else { } else {
x1 = x1 + 20 x1 = x1 + edge
x2 = x2 - 20 x2 = x2 - edge
y1 = y1 - 50 y1 = y1 - eaves
y2 = y2 - 50 y2 = y2 - eaves
} }
} }
switch (polygon.shape) { switch (polygon.shape) {
case 1: case 1:
break
case 2:
const centerPoint =
polygon.points[3].y +
(polygon.points[2].y - polygon.points[3].y) / 2
if (index === 0) { if (index === 0) {
const subLine = new QLine( const subLine = new QLine(
[ [
point.x - 20, point.x - edge,
polygon.points[0].y + polygon.points[0].y + (polygon.points[1].y - polygon.points[0].y) / 2,
(polygon.points[1].y - polygon.points[0].y) / 2, polygon.points[2].x,
polygon.points[5].x + 20, polygon.points[0].y + (polygon.points[1].y - polygon.points[0].y) / 2,
polygon.points[0].y + ],
(polygon.points[1].y - polygon.points[0].y) / 2, {
stroke: 'blue',
strokeWidth: 2,
selectable: false,
fontSize: fontSize,
},
)
canvas.add(subLine)
}
if (index === 1) {
x2 = x2 - edge
const subLine = new QLine([x2, y2, x2, polygon.points[0].y + (polygon.points[1].y - polygon.points[0].y) / 2], {
stroke: 'blue',
strokeWidth: 2,
selectable: false,
fontSize: fontSize,
})
canvas.add(subLine)
}
if (index === 2) {
y1 = point.y - (polygon.points[1].y - polygon.points[0].y) / 2
const centeredPoint = getCenterPoint(polygon.points[1].x, point.x)
const subLine = new QLine(
[centeredPoint, point.y + eaves, centeredPoint, polygon.points[0].y + (polygon.points[1].y - polygon.points[0].y) / 2],
{
stroke: 'black',
strokeWidth: 2,
strokeDashArray: [5, 5],
selectable: false,
fontSize: fontSize,
},
)
canvas.add(subLine)
}
if (index === 3) {
const centeredPoint = getCenterPoint(point.x, polygon.points[4].x)
const subLine = new QLine([centeredPoint, point.y + eaves, centeredPoint, polygon.points[5].y - eaves], {
stroke: 'black',
strokeWidth: 2,
strokeDashArray: [5, 5],
selectable: false,
fontSize: fontSize,
})
canvas.add(subLine)
}
if (index === 5) {
const centeredPoint = getCenterPoint(point.y, polygon.points[4].y)
const subLine = new QLine([point.x + edge, centeredPoint, polygon.points[2].x - edge, centeredPoint], {
stroke: 'blue',
strokeWidth: 2,
selectable: false,
fontSize: fontSize,
})
canvas.add(subLine)
}
break
case 2:
const centerPoint = polygon.points[3].y + (polygon.points[2].y - polygon.points[3].y) / 2
if (index === 0) {
const subLine = new QLine(
[
point.x - egde,
polygon.points[0].y + (polygon.points[1].y - polygon.points[0].y) / 2,
polygon.points[5].x + egde,
polygon.points[0].y + (polygon.points[1].y - polygon.points[0].y) / 2,
], ],
{ {
stroke: 'blue', stroke: 'blue',
@ -1002,7 +1057,7 @@ export function useMode() {
canvas.add(subLine) canvas.add(subLine)
} }
if (index === 3) { if (index === 3) {
x2 = x2 + 20 x2 = x2 + egde
const subLine = new QLine([x2, y2, x2, centerPoint], { const subLine = new QLine([x2, y2, x2, centerPoint], {
stroke: 'blue', stroke: 'blue',
@ -1013,26 +1068,20 @@ export function useMode() {
canvas.add(subLine) canvas.add(subLine)
} }
if (index === 4) { if (index === 4) {
y1 = y1 = point.y + (polygon.points[index - 2].y - polygon.points[index - 1].y) / 2
point.y +
(polygon.points[index - 2].y - polygon.points[index - 1].y) / 2
const subLine = new QLine( const subLine = new QLine([point.x, centerPoint, polygon.points[2].x + 20, centerPoint], {
[point.x, centerPoint, polygon.points[2].x + 20, centerPoint], stroke: 'blue',
{ strokeWidth: 2,
stroke: 'blue', selectable: false,
strokeWidth: 2, fontSize: fontSize,
selectable: false, })
fontSize: fontSize,
},
)
canvas.add(subLine)
const subVerticalLine = new QLine( const subVerticalLine = new QLine(
[ [
getCenterPoint(point.x, polygon.points[2].x + 20), getCenterPoint(point.x, polygon.points[2].x + egde),
polygon.points[3].y - 50, polygon.points[3].y - eaves,
getCenterPoint(point.x, polygon.points[2].x + 20), getCenterPoint(point.x, polygon.points[2].x + egde),
centerPoint, centerPoint,
], ],
{ {
@ -1047,25 +1096,14 @@ export function useMode() {
} }
if (index === 5) { if (index === 5) {
const centeredPoint = getCenterPoint( const centeredPoint = getCenterPoint(polygon.points[0].x, polygon.points[5].x)
polygon.points[0].x, const verticalSubLine = new QLine([centeredPoint, polygon.points[0].y - eaves, centeredPoint, polygon.points[1].y + eaves], {
polygon.points[5].x, stroke: 'black',
) strokeWidth: 2,
const verticalSubLine = new QLine( strokeDashArray: [5, 5],
[ selectable: false,
centeredPoint, fontSize: fontSize,
polygon.points[0].y - 50, })
centeredPoint,
polygon.points[1].y + 50,
],
{
stroke: 'black',
strokeWidth: 2,
strokeDashArray: [5, 5],
selectable: false,
fontSize: fontSize,
},
)
canvas.add(verticalSubLine) canvas.add(verticalSubLine)
} }
@ -1100,6 +1138,5 @@ export function useMode() {
zoom, zoom,
togglePolygonLine, togglePolygonLine,
handleOuterlinesTest2, handleOuterlinesTest2,
applyTemplateB,
} }
} }