Merge branch 'feature/test' into feature/test-jy

This commit is contained in:
Jaeyoung Lee 2024-07-23 09:56:17 +09:00
commit f9939c4c1e
4 changed files with 230 additions and 47 deletions

View File

@ -29,8 +29,19 @@ export default function Roof2() {
const [showControl, setShowControl] = useState(false)
const { mode, changeMode, handleClear, fillCellInPolygon, zoomIn, zoomOut, zoom, togglePolygonLine, handleOuterlinesTest2, applyTemplateB } =
useMode()
const {
mode,
changeMode,
handleClear,
fillCellInPolygon,
zoomIn,
zoomOut,
zoom,
togglePolygonLine,
handleOuterlinesTest2,
applyTemplateB,
makeRoofPatternPolygon,
} = useMode()
useEffect(() => {
if (!canvas) {
@ -240,6 +251,10 @@ export default function Roof2() {
setShowControl(!showControl)
}
const drawRoofPatterns = (roofStyle) => {
makeRoofPatternPolygon(roofStyle)
}
return (
<>
{canvas && (
@ -267,6 +282,12 @@ export default function Roof2() {
<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>

View File

@ -1,15 +1,9 @@
import { useRef, useState } from 'react'
import QRect from '@/components/fabric/QRect'
import QPolygon from '@/components/fabric/QPolygon'
import {
findTopTwoIndexesByDistance,
getCenterPoint,
getDirection,
getStartIndex,
rearrangeArray,
} from '@/util/canvas-util'
import { findTopTwoIndexesByDistance, getCenterPoint, getDirection, getStartIndex, rearrangeArray } from '@/util/canvas-util'
import { useRecoilState } from 'recoil'
import { fontSizeState, roofState, sortedPolygonArray, templatePolygonArrayState, wallState } from '@/store/canvasAtom'
import { fontSizeState, roofState, sortedPolygonArray, roofPolygonPatternArrayState, wallState } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
export const Mode = {
@ -20,6 +14,7 @@ export const Mode = {
PATTERNB: 'patternb',
TEXTBOX: 'textbox',
DRAW_RECT: 'drawRect',
ROOF_PATTERN: 'roofPattern',
DEFAULT: 'default',
}
@ -35,7 +30,7 @@ export function useMode() {
const [sortedArray, setSortedArray] = useRecoilState(sortedPolygonArray)
const [roof, setRoof] = useRecoilState(roofState)
const [wall, setWall] = useRecoilState(wallState)
const [templatePolygonState, setTemplatePolygonState] = useRecoilState(templatePolygonArrayState)
const [roofPolygonPattern, setRoofPolygonPattern] = useRecoilState(roofPolygonPatternArrayState)
const addEvent = (mode) => {
switch (mode) {
@ -63,6 +58,9 @@ export function useMode() {
case 'drawRect':
drawRectMode()
break
case 'roofPattern':
makeRoofPatternPolygon()
break
}
}
@ -75,7 +73,7 @@ export function useMode() {
}
const editMode = () => {
canvas?.on('mouse:down', function(options) {
canvas?.on('mouse:down', function (options) {
const pointer = canvas?.getPointer(options.e)
const circle = new fabric.Circle({
radius: 1,
@ -226,7 +224,7 @@ export function useMode() {
}
const textboxMode = () => {
canvas?.on('mouse:down', function(options) {
canvas?.on('mouse:down', function (options) {
if (canvas?.getActiveObject()?.type === 'textbox') return
const pointer = canvas?.getPointer(options.e)
@ -241,14 +239,14 @@ export function useMode() {
canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다.
canvas?.renderAll()
// textbox가 active가 풀린 경우 editing mode로 변경
textbox?.on('editing:exited', function() {
textbox?.on('editing:exited', function () {
changeMode(canvas, Mode.EDIT)
})
})
}
const drawLineMode = () => {
canvas?.on('mouse:down', function(options) {
canvas?.on('mouse:down', function (options) {
const pointer = canvas?.getPointer(options.e)
const line = new QLine(
@ -269,7 +267,7 @@ export function useMode() {
const drawRectMode = () => {
let rect, isDown, origX, origY
canvas.on('mouse:down', function(o) {
canvas.on('mouse:down', function (o) {
isDown = true
const pointer = canvas.getPointer(o.e)
origX = pointer.x
@ -289,7 +287,7 @@ export function useMode() {
canvas.add(rect)
})
canvas.on('mouse:move', function(o) {
canvas.on('mouse:move', function (o) {
if (!isDown) return
const pointer = canvas.getPointer(o.e)
if (origX > pointer.x) {
@ -303,7 +301,7 @@ export function useMode() {
rect.set({ height: Math.abs(origY - pointer.y) })
})
canvas.on('mouse:up', function(o) {
canvas.on('mouse:up', function (o) {
const pointer = canvas.getPointer(o.e)
const qRect = new QRect({
left: origX,
@ -1171,7 +1169,6 @@ export function useMode() {
)
canvas.add(horiCenterLine2)
//작은 지붕쪽 높이 길이를 구하는 로직
let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2
secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1, secondVertCenterPoint, middleSubLine.y2 - edge], centerLineOpt)
@ -1251,17 +1248,33 @@ export function useMode() {
centerLineOpt,
)
canvas.add(drawLastInLine1)
outLines.push(drawLastInLine1)
let drawLastInLine2 = new QLine([secondVertCenterLine.x1, vertCenterLine.y2, vertCenterLine.x2, vertCenterLine.y2], centerLineOpt)
canvas.add(drawLastInLine2)
outLines.push(drawLastInLine2)
const bigPolygon = [
{ x1: outLines[2].x1, y1: outLines[2].y1 },
const bigRoofPolygon = [
{ x: outLines[2].x1, y: outLines[2].y1 },
{ x: outLines[2].x2, y: outLines[2].y2 },
{ x: outLines[0].x1, y: outLines[0].y1 },
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[1].x2, y: outLines[0].y2 },
{ x: outLines[1].x2, y: outLines[1].y2 },
]
const middleRoofPolygon = [
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[0].x1, y: outLines[0].y1 },
{ x: outLines[3].x2, y: outLines[3].y2 },
{ x: outLines[3].x1, y: outLines[3].y1 },
]
const smallRoofPolygon = [
{ x: outLines[1].x2, y: outLines[1].y2 },
{ x: outLines[1].x1, y: outLines[1].y1 },
{ x: outLines[4].x2, y: outLines[4].y2 },
{ x: outLines[4].x1, y: outLines[4].y1 },
]
setRoofPolygonPattern({ bigRoofPolygon, middleRoofPolygon, smallRoofPolygon, lines })
} else {
//아래쪽 길게 오른쪽 방향
//배열 순서대로 뒤에꺼를 찾아서 계산한다
@ -1286,6 +1299,7 @@ export function useMode() {
centerLineOpt,
)
canvas.add(vertCenterLine)
outLines.push(vertCenterLine)
//긴면 가로선 그리기
let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2
@ -1309,8 +1323,8 @@ export function useMode() {
//작은 지붕쪽 높이 길이를 구하는 로직
let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2
secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1 - edge, secondVertCenterPoint, middleSubLine.y2], centerLineOpt)
canvas.add(secondVertCenterLine)
outLines.push(secondVertCenterLine)
//작은 지붕쪽 너비 길이를 구한는 로직
let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2
@ -1334,6 +1348,7 @@ export function useMode() {
}
let drawline = new QLine(points, centerLineOpt)
canvas.add(drawline)
outLines.push(drawline)
})
//케라바 라인 외각선 그리기
@ -1348,6 +1363,7 @@ export function useMode() {
centerLineOpt,
)
canvas.add(drawFirstLine1)
outLines.push(drawFirstLine1)
//첫번째 외곽선 2번
let drawFirstLine2 = new QLine(
@ -1355,16 +1371,16 @@ export function useMode() {
centerLineOpt,
)
canvas.add(drawFirstLine2)
outLines.push(drawFirstLine2)
//중간라인 외각선
let drawMiddleLine = new QLine([drawFirstLine1.x1, middleOuterLine.y1 - edge, drawFirstLine1.x2, middleOuterLine.y2 - edge], centerLineOpt)
canvas.add(drawMiddleLine)
outLines.push(drawMiddleLine)
//마지막 외각선
halfLength = lastLine.length / 2
console.log(lastOuterLine)
let drawLastLine1 = new QLine(
[lastOuterLine.x2 - eaves, lastOuterLine.y1 - edge, lastOuterLine.x1 - halfLength, lastOuterLine.y2 - edge],
centerLineOpt,
@ -1385,6 +1401,30 @@ export function useMode() {
let drawLastInLine2 = new QLine([secondVertCenterLine.x2, vertCenterLine.y1, vertCenterLine.x1, vertCenterLine.y1], centerLineOpt)
canvas.add(drawLastInLine2)
const bigRoofPolygon = [
{ x: outLines[0].x1, y: outLines[0].y1 },
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[3].x1, y: outLines[3].y1 },
{ x: outLines[3].x2, y: outLines[3].y2 },
{ x: outLines[1].x1, y: outLines[1].y1 },
{ x: outLines[1].x2, y: outLines[0].y1 },
]
const middleRoofPolygon = [
{ x: outLines[2].x1, y: outLines[2].y1 },
{ x: outLines[2].x2, y: outLines[2].y2 },
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[0].x1, y: outLines[0].y1 },
]
const smallRoofPolygon = [
{ x: outLines[4].x1, y: outLines[4].y1 },
{ x: outLines[4].x2, y: outLines[4].y2 },
{ x: outLines[1].x2, y: outLines[1].y2 },
{ x: outLines[1].x1, y: outLines[1].y1 },
]
setRoofPolygonPattern({ bigRoofPolygon, middleRoofPolygon, smallRoofPolygon, lines })
}
} else {
if (horizontalDirection === 'left') {
@ -1410,6 +1450,7 @@ export function useMode() {
centerLineOpt,
)
canvas.add(vertCenterLine)
outLines.push(vertCenterLine)
//긴면 가로선 그리기
let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2
@ -1434,6 +1475,7 @@ export function useMode() {
let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2
secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1 + edge, secondVertCenterPoint, middleSubLine.y2], centerLineOpt)
canvas.add(secondVertCenterLine)
outLines.push(secondVertCenterLine)
//작은 지붕쪽 너비 길이를 구한는 로직
let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2
@ -1457,6 +1499,7 @@ export function useMode() {
let drawline = new QLine(points, centerLineOpt)
canvas.add(drawline)
outLines.push(drawline)
})
//케라바 라인 외각선 그리기
@ -1485,9 +1528,6 @@ export function useMode() {
//마지막 외각선
halfLength = lastLine.length / 2
console.log(lastOuterLine)
let drawLastLine1 = new QLine(
[lastOuterLine.x1 - eaves, lastOuterLine.y1 + edge, lastOuterLine.x1 + halfLength, lastOuterLine.y2 + edge],
centerLineOpt,
@ -1505,6 +1545,31 @@ export function useMode() {
let drawLastInLine2 = new QLine([vertCenterLine.x1, vertCenterLine.y2, secondVertCenterLine.x2, vertCenterLine.y2], centerLineOpt)
canvas.add(drawLastInLine2)
const bigRoofPolygon = [
{ x: outLines[2].x1, y: outLines[2].y1 },
{ x: outLines[2].x2, y: outLines[2].y2 },
{ x: outLines[1].x1, y: outLines[1].y1 },
{ x: outLines[1].x2, y: outLines[0].y2 },
{ x: outLines[0].x1, y: outLines[0].y2 },
{ x: outLines[0].x1, y: outLines[0].y1 },
]
const middleRoofPolygon = [
{ x: outLines[0].x1, y: outLines[0].y1 },
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[4].x2, y: outLines[4].y2 },
{ x: outLines[4].x1, y: outLines[4].y1 },
]
const smallRoofPolygon = [
{ x: outLines[1].x2, y: outLines[1].y2 },
{ x: outLines[1].x1, y: outLines[1].y1 },
{ x: outLines[3].x2, y: outLines[3].y2 },
{ x: outLines[3].x1, y: outLines[3].y1 },
]
setRoofPolygonPattern({ bigRoofPolygon, middleRoofPolygon, smallRoofPolygon, lines })
} else {
//윗쪽 길게 오른쪽 방향
//배열 순서대로 뒤에꺼를 찾아서 계산한다
@ -1528,6 +1593,7 @@ export function useMode() {
centerLineOpt,
)
canvas.add(vertCenterLine)
outLines.push(vertCenterLine)
//긴면 가로선 그리기
let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2
@ -1558,7 +1624,7 @@ export function useMode() {
})
canvas.add(secondVertCenterLine)
outLines.push(secondVertCenterLine)
//작은 지붕쪽 너비 길이를 구한는 로직
let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2
let secondHoriCenterPoint = (secondVertCenterLine.y1 + secondVertCenterLine.y2) / 2
@ -1572,14 +1638,16 @@ export function useMode() {
//일반라인 외각선 그리기
normalIndexArray.forEach((index) => {
const line = lines[index]
let drawline
if (index === 0 || index === 2) {
let tmpEdge = index === 2 ? 0 : edge
let drawline = new QLine([line.x1 - eaves, line.y1 - tmpEdge, line.x2 - eaves, line.y2 + edge], centerLineOpt)
drawline = new QLine([line.x1 - eaves, line.y1 - tmpEdge, line.x2 - eaves, line.y2 + edge], centerLineOpt)
canvas.add(drawline)
} else {
let drawline = new QLine([line.x1 + eaves, line.y1 + edge, line.x2 + eaves, line.y2 - edge], centerLineOpt)
drawline = new QLine([line.x1 + eaves, line.y1 + edge, line.x2 + eaves, line.y2 - edge], centerLineOpt)
canvas.add(drawline)
}
outLines.push(drawline)
})
//케라바 라인 외각선 그리기
@ -1622,6 +1690,31 @@ export function useMode() {
let drawLastInLine2 = new QLine([secondLine.x2 - eaves, secondLine.y1, drawLastLine1.x2, secondLine.y1], centerLineOpt)
canvas.add(drawLastInLine2)
const bigRoofPolygon = [
{ x: outLines[0].x1, y: outLines[0].y1 },
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[1].x1, y: outLines[0].y2 },
{ x: outLines[1].x2, y: outLines[1].y2 },
{ x: outLines[4].x1, y: outLines[4].y1 },
{ x: outLines[4].x2, y: outLines[4].y2 },
]
const middleRoofPolygon = [
{ x: outLines[2].x1, y: outLines[2].y1 },
{ x: outLines[2].x2, y: outLines[2].y2 },
{ x: outLines[0].x2, y: outLines[0].y2 },
{ x: outLines[0].x1, y: outLines[0].y1 },
]
const smallRoofPolygon = [
{ x: outLines[3].x1, y: outLines[3].y1 },
{ x: outLines[3].x2, y: outLines[3].y2 },
{ x: outLines[1].x2, y: outLines[1].y2 },
{ x: outLines[1].x1, y: outLines[1].y1 },
]
setRoofPolygonPattern({ bigRoofPolygon, middleRoofPolygon, smallRoofPolygon, lines })
}
}
@ -2047,6 +2140,74 @@ export function useMode() {
canvas.renderAll()
}
const makeRoofPatternPolygon = (roofStyle) => {
if (Object.keys(roofPolygonPattern).length === 0 && roofPolygonPattern.constructor === Object) {
alert('객체가 비어있습니다.')
return
}
//내부 선 점선으로 변경
roofPolygonPattern.lines.forEach((line, index) => {
line.line.set('strokeDashArray', [10, 5, 2, 5])
line.line.set('stroke', 'blue')
line.line.set('strokeWidth', 1)
})
var ratio = window.devicePixelRatio || 1
// 패턴 소스를 위한 임시 캔버스 생성
const patternSourceCanvas = document.createElement('canvas')
patternSourceCanvas.width = 30 * ratio
patternSourceCanvas.height = 30 * ratio
const ctx = patternSourceCanvas.getContext('2d')
// 벽돌 패턴 그리기
ctx.scale(ratio, ratio)
ctx.strokeStyle = 'green'
ctx.lineWidth = 0.2
// 첫 번째 행 벽돌
if (roofStyle === 2) {
//지그재그
// // 두 번째 행 벽돌
ctx.strokeRect(0, 0, 30, 15)
ctx.strokeRect(30, 15, 30, 15)
ctx.strokeRect(-15, 15, 30, 15)
ctx.strokeRect(0, 30, 30, 15)
} else {
ctx.strokeRect(0, 0, 30, 30) // 원패턴일때랑 지그재그일때랑은 다르게 들어가야함
}
// 패턴 생성
const pattern = new fabric.Pattern({
source: patternSourceCanvas,
repeat: 'repeat',
})
const commonOption = {
fill: pattern,
selectable: false,
fontSize: 15, // fontSize는 필요에 따라 조정
}
const bigRoof = new QPolygon(roofPolygonPattern.bigRoofPolygon, commonOption)
const middleRoof = new QPolygon(roofPolygonPattern.middleRoofPolygon, commonOption)
const smallRoof = new QPolygon(roofPolygonPattern.smallRoofPolygon, commonOption)
bigRoof.setViewLengthText(false) //치수 필요없음
middleRoof.setViewLengthText(false)
smallRoof.setViewLengthText(false)
bigRoof.sendToBack() //객체를 가장 뒤로
middleRoof.sendToBack()
smallRoof.sendToBack()
canvas.add(bigRoof) //캔버스 객체 추가
canvas.add(middleRoof)
canvas.add(smallRoof)
canvas.renderAll()
}
return {
mode,
changeMode,
@ -2057,5 +2218,6 @@ export function useMode() {
zoom,
togglePolygonLine,
handleOuterlinesTest2,
makeRoofPatternPolygon,
}
}

View File

@ -36,8 +36,8 @@ export const wallState = atom({
dangerouslyAllowMutability: true,
})
export const templatePolygonArrayState = atom({
key: 'templatePolygon',
export const roofPolygonPatternArrayState = atom({
key: 'roofPolygonPattern',
default: {}, //object ex) big, mid, sht = {point : [{x1, y1}, {x2, y1}], direction : left or right or top or bottom}
dangerouslyAllowMutability: true,
})

View File

@ -38,7 +38,7 @@ export function actionHandler(eventData, transform, x, y) {
// define a function that can keep the polygon in the same position when we change its width/height/top/left
export function anchorWrapper(anchorIndex, fn) {
return function(eventData, transform, x, y) {
return function (eventData, transform, x, y) {
let fabricObject = transform.target
let originX = fabricObject?.points[anchorIndex].x - fabricObject.pathOffset.x
let originY = fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y
@ -365,11 +365,11 @@ export const sortedPoints = (points) => {
for (let i = 0; i < copyPoints.length; i++) {
// y값이 같은 point가 많은 경우 그 중 x값이 가장 큰걸 찾는다.
const temp = copyPoints.filter((point) => point.y === currentPoint.y)
// temp중 x값이 가장 큰 값
const max = temp.reduce((prev, current) => (prev.x >= current.x ? prev : current))
resultPoints.push(max)
currentPoint = max
copyPoints.splice(copyPoints.indexOf(max), 1)
// temp중 x값이 가장 큰 값 copyPoint보다 큰값
const min = temp.reduce((prev, current) => (prev.x <= current.x ? prev : current))
resultPoints.push(min)
currentPoint = min
copyPoints.splice(copyPoints.indexOf(min), 1)
index++
break
}
@ -378,12 +378,12 @@ export const sortedPoints = (points) => {
for (let i = 0; i < copyPoints.length; i++) {
// x값이 같은 point가 많은 경우 그 중 y값이 가장 큰걸 찾는다.
const temp = copyPoints.filter((point) => point.x === currentPoint.x)
// temp중 y값이 가장
const max = temp.reduce((prev, current) => (prev.y >= current.y ? prev : current))
// temp중 y값이 가장 작은
const min = temp.reduce((prev, current) => (prev.y <= current.y ? prev : current))
resultPoints.push(max)
currentPoint = max
copyPoints.splice(copyPoints.indexOf(max), 1)
resultPoints.push(min)
currentPoint = min
copyPoints.splice(copyPoints.indexOf(min), 1)
index++
break
}
@ -447,4 +447,4 @@ export function calculateDistance(point, line) {
const numerator = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1)
const denominator = Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2))
return numerator / denominator
}
}