From 86522f67e10cc5ea533b283534cf2d698f77ed65 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 20 Jun 2024 16:47:22 +0900 Subject: [PATCH 001/113] =?UTF-8?q?group=20=EC=88=AB=EC=9E=90=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof.jsx | 122 ++++++++++++++++++++++++++++++---------- src/hooks/useCanvas.js | 3 +- 2 files changed, 94 insertions(+), 31 deletions(-) diff --git a/src/components/Roof.jsx b/src/components/Roof.jsx index 0ff0e9ba..4da324c1 100644 --- a/src/components/Roof.jsx +++ b/src/components/Roof.jsx @@ -2,6 +2,7 @@ import { createGroupWithLineAndText, getDistance } from '@/app/util/canvas-util' import { useCanvas } from '@/hooks/useCanvas' import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' +import { useEffect } from 'react' export default function Roof() { const { @@ -21,6 +22,19 @@ export default function Roof() { updateTextOnLineChange, } = useCanvas('canvas') + useEffect(() => { + // IText 추가 + const text = new fabric.IText('Hello', { + left: 100, + top: 100, + fill: 'red', + }) + text.on('editing:entered', () => { + console.log('editing:entered') + }) + canvas?.add(text) + }, [canvas]) + const addRect = () => { const rect = new fabric.Rect({ height: 200, @@ -92,9 +106,9 @@ export default function Roof() { const trapezoid = new fabric.Polygon( [ { x: 100, y: 100 }, // 좌상단 - { x: 300, y: 100 }, // 우상단 - { x: 250, y: 200 }, // 우하단 - { x: 150, y: 200 }, // 좌하단 + { x: 500, y: 100 }, // 우상단 + { x: 750, y: 400 }, // 우하단 + { x: 250, y: 400 }, // 좌하단 ], { name: uuidv4(), @@ -102,35 +116,89 @@ export default function Roof() { opacity: 0.4, strokeWidth: 3, selectable: true, + objectCaching: false, }, ) - attachCustomControlOnPolygon(trapezoid) - addShape(trapezoid) + // attachCustomControlOnPolygon(trapezoid) + + const group = addDistanceTextToPolygon(trapezoid) + addGroupClickEvent(group) + group.getObjects().forEach(function (object, index) { + if (object.type === 'i-text') { + addTextModifiedEvent(object, trapezoid, index) + } + }) + canvas?.add(group) + canvas?.renderAll() } - const addTextWithLine = () => { - const { x1, y1, x2, y2 } = { x1: 20, y1: 100, x2: 220, y2: 100 } - /** - * 시작X,시작Y,도착X,도착Y 좌표 - */ - const horizontalLine = new fabric.Line([x1, y1, x2, y2], { - name: uuidv4(), - stroke: 'red', - strokeWidth: 3, + // group에 클릭 이벤트를 추가하여 클릭 시 group을 제거하고 object들만 남기는 함수 + function addGroupClickEvent(group) { + group.on('mousedown', function () { + const objects = group.getObjects() + canvas?.remove(group) + objects.forEach(function (object) { + canvas?.add(object) + }) + canvas?.renderAll() + }) + } + + // polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수 + function addDistanceTextToPolygon(polygon) { + const points = polygon.get('points') + const texts = [] + + for (let i = 0; i < points.length; i++) { + const start = points[i] + const end = points[(i + 1) % points.length] // 다음 점 (마지막 점의 경우 첫번째 점으로) + const distance = Math.sqrt( + Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2), + ) // 두 점 사이의 거리 계산 + + const text = new fabric.IText(distance.toFixed(2), { + // 소수 둘째자리까지 표시 + left: (start.x + end.x) / 2, // 텍스트의 위치는 두 점의 중간 + top: (start.y + end.y) / 2, + fontSize: 10, + editable: true, + }) + + texts.push(text) + } + + return new fabric.Group([polygon, ...texts], { + // polygon과 텍스트들을 그룹화 selectable: true, }) + } - const text = new fabric.Text(getDistance(x1, y1, x2, y2).toString(), { - fontSize: 20, - left: (x2 - x1) / 2, - top: y1 - 20, + // IText를 수정할 때 해당 값을 길이로 갖는 다른 polygon을 생성하고 다시 그룹화하는 함수 + function addTextModifiedEvent(text, polygon, index) { + text.on('editing:entered', function () { + console.log(123) + const newLength = parseFloat(text.text) + const points = polygon.get('points') + const start = points[index] + const end = points[(index + 1) % points.length] + const vector = { x: end.x - start.x, y: end.y - start.y } // start에서 end로의 벡터 + const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y) // 벡터의 길이 (현재 거리) + const normalizedVector = { x: vector.x / length, y: vector.y / length } // 벡터를 정규화 (길이를 1로) + const scaledVector = { + x: normalizedVector.x * newLength, + y: normalizedVector.y * newLength, + } // 정규화된 벡터를 새로운 길이로 스케일링 + + // end 점을 새로운 위치로 이동 + end.x = start.x + scaledVector.x + end.y = start.y + scaledVector.y + + // polygon을 다시 그룹화 + const newGroup = addDistanceTextToPolygon(polygon) + addGroupClickEvent(newGroup) + canvas.add(newGroup) + canvas.renderAll() }) - - const group = createGroupWithLineAndText(horizontalLine, text) - addShape(group) - - // 선의 길이가 변경될 때마다 텍스트를 업데이트하는 이벤트 리스너를 추가합니다. - group.on('modified', () => updateTextOnLineChange(group, text)) } const randomColor = () => { @@ -232,12 +300,6 @@ export default function Roof() { > 도형반전 -
Date: Fri, 21 Jun 2024 10:21:13 +0900 Subject: [PATCH 002/113] =?UTF-8?q?=EC=9A=B0=EC=84=A0=20=EC=88=AB=EC=9E=90?= =?UTF-8?q?=20=EB=8D=94=EB=B8=94=ED=81=B4=EB=A6=AD=20=EC=8B=9C=20=EC=88=AB?= =?UTF-8?q?=EC=9E=90=EB=A7=8C=20=EC=88=98=EC=A0=95=20=EA=B0=80=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/util/canvas-util.js | 46 ++++---- src/components/Roof.jsx | 213 ++++++++++++++++++++++++------------ src/hooks/useCanvas.js | 9 -- 3 files changed, 170 insertions(+), 98 deletions(-) diff --git a/src/app/util/canvas-util.js b/src/app/util/canvas-util.js index c052986b..1cd367fc 100644 --- a/src/app/util/canvas-util.js +++ b/src/app/util/canvas-util.js @@ -77,23 +77,31 @@ export function anchorWrapper(anchorIndex, fn) { export const getDistance = (x1, y1, x2, y2) => { return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) } -// 선의 길이를 계산하는 함수 -export const calculateLineLength = (x1, y1, x2, y2) => { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) -} - -// 선과 텍스트를 그룹으로 묶는 함수 -export const createGroupWithLineAndText = (line, text) => { - return new fabric.Group([line, text]) -} - -export const calculateShapeLength = (shape) => { - // 도형의 원래 길이를 가져옵니다. - const originalLength = shape.width - - // 도형의 scaleX 값을 가져옵니다. - const scaleX = shape.scaleX - - // 도형의 현재 길이를 계산합니다. - return originalLength * scaleX + +// polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수 +export function addDistanceTextToPolygon(polygon) { + const points = polygon.get('points') + const texts = [] + + for (let i = 0; i < points.length; i++) { + const start = points[i] + const end = points[(i + 1) % points.length] // 다음 점 (마지막 점의 경우 첫번째 점으로) + const distance = Math.sqrt( + Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2), + ) // 두 점 사이의 거리 계산 + + const text = new fabric.Textbox(distance.toFixed(2), { + // 소수 둘째자리까지 표시 + left: (start.x + end.x) / 2, // 텍스트의 위치는 두 점의 중간 + top: (start.y + end.y) / 2, + fontSize: 20, + }) + + texts.push(text) + } + + return new fabric.Group([polygon, ...texts], { + // polygon과 텍스트들을 그룹화 + selectable: true, + }) } diff --git a/src/components/Roof.jsx b/src/components/Roof.jsx index 4da324c1..3a90b960 100644 --- a/src/components/Roof.jsx +++ b/src/components/Roof.jsx @@ -1,4 +1,4 @@ -import { createGroupWithLineAndText, getDistance } from '@/app/util/canvas-util' +import { addDistanceTextToPolygon, getDistance } from '@/app/util/canvas-util' import { useCanvas } from '@/hooks/useCanvas' import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' @@ -19,20 +19,86 @@ export default function Roof() { attachCustomControlOnPolygon, saveImage, handleFlip, - updateTextOnLineChange, } = useCanvas('canvas') useEffect(() => { - // IText 추가 - const text = new fabric.IText('Hello', { + let circle = new fabric.Circle({ + radius: 40, + fill: 'rgba(200, 0, 0, 0.3)', + originX: 'center', + originY: 'center', + }) + + let text = new fabric.Textbox('AJLoveChina', { + originX: 'center', + originY: 'center', + textAlign: 'center', + fontSize: 12, + }) + + let group = new fabric.Group([circle, text], { left: 100, top: 100, - fill: 'red', + originX: 'center', + originY: 'center', }) - text.on('editing:entered', () => { - console.log('editing:entered') + + group.on('mousedblclick', () => { + // textForEditing is temporary obj, + // and will be removed after editing + console.log(text.type) + let textForEditing = new fabric.Textbox(text.text, { + originX: 'center', + originY: 'center', + textAlign: text.textAlign, + fontSize: text.fontSize, + + left: group.left, + top: group.top, + }) + + // hide group inside text + text.visible = false + // note important, text cannot be hidden without this + group.addWithUpdate() + + textForEditing.visible = true + // do not give controls, do not allow move/resize/rotation on this + textForEditing.hasConstrols = false + + // now add this temporary obj to canvas + canvas.add(textForEditing) + canvas.setActiveObject(textForEditing) + // make the cursor showing + textForEditing.enterEditing() + textForEditing.selectAll() + + // editing:exited means you click outside of the textForEditing + textForEditing.on('editing:exited', () => { + let newVal = textForEditing.text + let oldVal = text.text + + // then we check if text is changed + if (newVal !== oldVal) { + text.set({ + text: newVal, + visible: true, + }) + + // comment before, you must call this + group.addWithUpdate() + + // we do not need textForEditing anymore + textForEditing.visible = false + canvas?.remove(textForEditing) + + // optional, buf for better user experience + canvas?.setActiveObject(group) + } + }) }) - canvas?.add(text) + + canvas?.add(group) }, [canvas]) const addRect = () => { @@ -107,7 +173,7 @@ export default function Roof() { [ { x: 100, y: 100 }, // 좌상단 { x: 500, y: 100 }, // 우상단 - { x: 750, y: 400 }, // 우하단 + { x: 750, y: 700 }, // 우하단 { x: 250, y: 400 }, // 좌하단 ], { @@ -119,86 +185,93 @@ export default function Roof() { objectCaching: false, }, ) - // attachCustomControlOnPolygon(trapezoid) - + attachCustomControlOnPolygon(trapezoid) const group = addDistanceTextToPolygon(trapezoid) addGroupClickEvent(group) - group.getObjects().forEach(function (object, index) { - if (object.type === 'i-text') { - addTextModifiedEvent(object, trapezoid, index) - } - }) canvas?.add(group) canvas?.renderAll() } // group에 클릭 이벤트를 추가하여 클릭 시 group을 제거하고 object들만 남기는 함수 function addGroupClickEvent(group) { - group.on('mousedown', function () { - const objects = group.getObjects() - canvas?.remove(group) - objects.forEach(function (object) { - canvas?.add(object) - }) - canvas?.renderAll() + group.on('selected', (e) => { + console.log(e) }) - } + group.on('mousedblclick', (e) => { + // textForEditing is temporary obj, + // and will be removed after editing + const pointer = canvas?.getPointer(e.e) // 마우스 클릭 위치 가져오기 + let minDistance = Infinity + let closestTextbox = null + const groupPoint = group.getCenterPoint() + group.getObjects().forEach(function (object) { + if (object.type === 'textbox') { + // 객체가 TextBox인지 확인 - // polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수 - function addDistanceTextToPolygon(polygon) { - const points = polygon.get('points') - const texts = [] + const objectCenter = object.getCenterPoint() // TextBox 객체의 중심점 가져오기 + const dx = objectCenter.x + groupPoint.x - pointer.x + const dy = objectCenter.y + groupPoint.y - pointer.y + const distance = Math.sqrt(dx * dx + dy * dy) // 마우스 클릭 위치와 TextBox 객체 사이의 거리 계산 - for (let i = 0; i < points.length; i++) { - const start = points[i] - const end = points[(i + 1) % points.length] // 다음 점 (마지막 점의 경우 첫번째 점으로) - const distance = Math.sqrt( - Math.pow(end.x - start.x, 2) + Math.pow(end.y - start.y, 2), - ) // 두 점 사이의 거리 계산 - - const text = new fabric.IText(distance.toFixed(2), { - // 소수 둘째자리까지 표시 - left: (start.x + end.x) / 2, // 텍스트의 위치는 두 점의 중간 - top: (start.y + end.y) / 2, - fontSize: 10, - editable: true, + if (distance < minDistance) { + // 가장 짧은 거리를 가진 TextBox 객체 찾기 + minDistance = distance + closestTextbox = object + } + } }) - texts.push(text) - } + let textForEditing = new fabric.Textbox(closestTextbox.text, { + originX: 'center', + originY: 'center', + textAlign: closestTextbox.textAlign, + fontSize: closestTextbox.fontSize, + left: closestTextbox.left + groupPoint.x, + top: closestTextbox.top + groupPoint.y, + }) - return new fabric.Group([polygon, ...texts], { - // polygon과 텍스트들을 그룹화 - selectable: true, + // hide group inside text + closestTextbox.visible = false + // note important, text cannot be hidden without this + group.addWithUpdate() + + textForEditing.visible = true + // do not give controls, do not allow move/resize/rotation on this + textForEditing.hasConstrols = false + + // now add this temporary obj to canvas + canvas?.add(textForEditing) + canvas?.setActiveObject(textForEditing) + // make the cursor showing + textForEditing?.enterEditing() + textForEditing?.selectAll() + + // editing:exited means you click outside of the textForEditing + textForEditing?.on('editing:exited', () => { + let newVal = textForEditing.text + + // then we check if text is changed + closestTextbox.set({ + text: newVal, + visible: true, + }) + + // comment before, you must call this + group.addWithUpdate() + + // we do not need textForEditing anymore + textForEditing.visible = false + canvas?.remove(textForEditing) + + // optional, buf for better user experience + canvas?.setActiveObject(group) + }) }) } // IText를 수정할 때 해당 값을 길이로 갖는 다른 polygon을 생성하고 다시 그룹화하는 함수 function addTextModifiedEvent(text, polygon, index) { - text.on('editing:entered', function () { - console.log(123) - const newLength = parseFloat(text.text) - const points = polygon.get('points') - const start = points[index] - const end = points[(index + 1) % points.length] - const vector = { x: end.x - start.x, y: end.y - start.y } // start에서 end로의 벡터 - const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y) // 벡터의 길이 (현재 거리) - const normalizedVector = { x: vector.x / length, y: vector.y / length } // 벡터를 정규화 (길이를 1로) - const scaledVector = { - x: normalizedVector.x * newLength, - y: normalizedVector.y * newLength, - } // 정규화된 벡터를 새로운 길이로 스케일링 - - // end 점을 새로운 위치로 이동 - end.x = start.x + scaledVector.x - end.y = start.y + scaledVector.y - - // polygon을 다시 그룹화 - const newGroup = addDistanceTextToPolygon(polygon) - addGroupClickEvent(newGroup) - canvas.add(newGroup) - canvas.renderAll() - }) + text.on('editing:exited', function () {}) } const randomColor = () => { diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 6d9559c1..9a188e58 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -3,7 +3,6 @@ import { fabric } from 'fabric' import { actionHandler, anchorWrapper, - calculateShapeLength, polygonPositionHandler, } from '@/app/util/canvas-util' @@ -495,13 +494,6 @@ export function useCanvas(id) { canvas?.renderAll() } - // 선의 길이가 변경될 때마다 텍스트를 업데이트하는 함수 - const updateTextOnLineChange = (group, text) => { - const length = calculateShapeLength(group) - text.set({ text: length.toString() }) - canvas?.renderAll() - } - return { canvas, addShape, @@ -516,6 +508,5 @@ export function useCanvas(id) { attachCustomControlOnPolygon, saveImage, handleFlip, - updateTextOnLineChange, } } From de380665f52a8121f1d7b058b60d19def5c1cda7 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 14:57:19 +0900 Subject: [PATCH 003/113] =?UTF-8?q?=EC=A0=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/roof2/page.jsx | 16 +++++ src/components/Headers.jsx | 1 + src/components/Roof2.jsx | 139 +++++++++++++++++++++++++++++++++++++ src/hooks/useCanvas.js | 5 +- 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/app/roof2/page.jsx create mode 100644 src/components/Roof2.jsx diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx new file mode 100644 index 00000000..03ab033c --- /dev/null +++ b/src/app/roof2/page.jsx @@ -0,0 +1,16 @@ +'use client' + +import Hero from '@/components/Hero' +import Roof from '@/components/Roof' +import Roof2 from '@/components/Roof2' + +export default function RoofPage() { + return ( + <> + +
+ +
+ + ) +} diff --git a/src/components/Headers.jsx b/src/components/Headers.jsx index c16bd077..c5161f0a 100644 --- a/src/components/Headers.jsx +++ b/src/components/Headers.jsx @@ -10,6 +10,7 @@ export default function Headers() {
Intro Roof + Roof2
diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx new file mode 100644 index 00000000..11dfa127 --- /dev/null +++ b/src/components/Roof2.jsx @@ -0,0 +1,139 @@ +import { useCanvas } from '@/hooks/useCanvas' +import { useEffect, useRef } from 'react' + +export default function Roof2() { + const { canvas } = useCanvas('canvas') + const points = useRef([]) + useEffect(() => { + canvas?.on('mouse:down', function (options) { + const pointer = canvas?.getPointer(options.e) + const circle = new fabric.Circle({ + radius: 5, + fill: 'transparent', // 원 안을 비웁니다. + stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. + left: pointer.x, + top: pointer.y, + originX: 'center', + originY: 'center', + selectable: false, + }) + + points.current.push(circle) + canvas?.add(circle) + + if (points.current.length === 2) { + const length = Number(prompt('길이를 입력하세요:')) + // length 값이 숫자가 아닌 경우 + if (isNaN(length) || length === 0) { + // 기존에 추가된 circle과 pointer를 제거합니다. + points.current.forEach((point) => { + canvas?.remove(point) + }) + points.current = [] + return + } + + if (length) { + const vector = { + x: points.current[1].left - points.current[0].left, + y: points.current[1].top - points.current[0].top, + } + const slope = Math.abs(vector.y / vector.x) // 기울기 계산 + + let scaledVector + if (slope >= 1) { + // 기울기가 1 이상이면 x축 방향으로 그림 + scaledVector = { + x: 0, + y: vector.y >= 0 ? Number(length) : -Number(length), + } + } else { + // 기울기가 1 미만이면 y축 방향으로 그림 + scaledVector = { + x: vector.x >= 0 ? Number(length) : -Number(length), + y: 0, + } + } + + let direction + if (Math.abs(vector.x) > Math.abs(vector.y)) { + // x축 방향으로 더 많이 이동 + direction = vector.x > 0 ? 'right' : 'left' + } else { + // y축 방향으로 더 많이 이동 + direction = vector.y > 0 ? 'bottom' : 'top' + } + + const line = new fabric.Line( + [ + points.current[0].left, + points.current[0].top, + points.current[0].left + scaledVector.x, + points.current[0].top + scaledVector.y, + ], + { + stroke: 'black', + strokeWidth: 2, + selectable: false, + direction: direction, + }, + ) + + const text = new fabric.Text(length.toString(), { + left: + (points.current[0].left + + points.current[0].left + + scaledVector.x) / + 2, + top: + (points.current[0].top + points.current[0].top + scaledVector.y) / + 2, + fontSize: 15, + originX: 'center', + originY: 'center', + selectable: false, + }) + + // 라인의 끝에 점을 추가합니다. + const endPointCircle = new fabric.Circle({ + radius: 5, + fill: 'transparent', // 원 안을 비웁니다. + stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. + left: points.current[0].left + scaledVector.x, + top: points.current[0].top + scaledVector.y, + originX: 'center', + originY: 'center', + selectable: false, + }) + + canvas?.add(line) + canvas?.add(text) + canvas?.add(endPointCircle) + points.current.forEach((point) => { + canvas?.remove(point) + }) + points.current = [endPointCircle] + } + } + + canvas?.renderAll() + }) + }, [canvas]) + return ( + <> +
+ +
+ +
+ + ) +} diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 9a188e58..aaeb0c7a 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -26,6 +26,7 @@ export function useCanvas(id) { height: CANVAS.HEIGHT, width: CANVAS.WIDTH, backgroundColor: 'white', + selection: false, }) // settings for all canvas in the app @@ -47,6 +48,8 @@ export function useCanvas(id) { useEffect(() => { if (canvas) { initialize() + canvas?.on('mouse:move', drawMouseLines) + canvas?.on('mouse:out', removeMouseLines) } }, [canvas]) const addEventOnCanvas = () => { @@ -91,7 +94,7 @@ export function useCanvas(id) { canvas?.clear() // 기존 이벤트가 있을 경우 제거한다. - removeEventOnCanvas() + // removeEventOnCanvas() // 작업 후에 event를 추가해준다. From f28b183c01046ac40761eb460a355c4de72d9c70 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 15:34:29 +0900 Subject: [PATCH 004/113] =?UTF-8?q?button=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 11dfa127..6c4de51e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -3,6 +3,7 @@ import { useEffect, useRef } from 'react' export default function Roof2() { const { canvas } = useCanvas('canvas') + const mode = useRef('') const points = useRef([]) useEffect(() => { canvas?.on('mouse:down', function (options) { @@ -121,7 +122,17 @@ export default function Roof2() { }, [canvas]) return ( <> -
+
+ + + +
Date: Mon, 24 Jun 2024 15:52:57 +0900 Subject: [PATCH 005/113] =?UTF-8?q?mode=20=EA=B4=80=EB=A0=A8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mode.js | 171 +++++++++++++++++++++++++++++++++++++++ src/components/Roof2.jsx | 141 +++++--------------------------- 2 files changed, 193 insertions(+), 119 deletions(-) create mode 100644 src/app/mode.js diff --git a/src/app/mode.js b/src/app/mode.js new file mode 100644 index 00000000..8911cd18 --- /dev/null +++ b/src/app/mode.js @@ -0,0 +1,171 @@ +import { useRef, useState } from 'react' + +export function useMode() { + const [mode, setMode] = useState(MODE.EDIT) + const points = useRef([]) + + const addEvent = (canvas, mode) => { + switch (mode) { + case 'edit': + editMode(canvas) + break + case 'template': + templateMode(canvas) + break + case 'textbox': + textboxMode(canvas) + break + } + } + + const changeMode = (canvas, mode) => { + setMode(mode) + // mode변경 시 이전 이벤트 제거 + canvas?.off('mouse:down') + + addEvent(canvas, mode) + } + + const editMode = (canvas) => { + canvas?.on('mouse:down', function (options) { + const pointer = canvas?.getPointer(options.e) + const circle = new fabric.Circle({ + radius: 5, + fill: 'transparent', // 원 안을 비웁니다. + stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. + left: pointer.x, + top: pointer.y, + originX: 'center', + originY: 'center', + selectable: false, + }) + + points.current.push(circle) + canvas?.add(circle) + + if (points.current.length === 2) { + const length = Number(prompt('길이를 입력하세요:')) + // length 값이 숫자가 아닌 경우 + if (isNaN(length) || length === 0) { + // 기존에 추가된 circle과 pointer를 제거합니다. + points.current.forEach((point) => { + canvas?.remove(point) + }) + points.current = [] + return + } + + if (length) { + const vector = { + x: points.current[1].left - points.current[0].left, + y: points.current[1].top - points.current[0].top, + } + const slope = Math.abs(vector.y / vector.x) // 기울기 계산 + + let scaledVector + if (slope >= 1) { + // 기울기가 1 이상이면 x축 방향으로 그림 + scaledVector = { + x: 0, + y: vector.y >= 0 ? Number(length) : -Number(length), + } + } else { + // 기울기가 1 미만이면 y축 방향으로 그림 + scaledVector = { + x: vector.x >= 0 ? Number(length) : -Number(length), + y: 0, + } + } + + let direction + if (Math.abs(vector.x) > Math.abs(vector.y)) { + // x축 방향으로 더 많이 이동 + direction = vector.x > 0 ? 'right' : 'left' + } else { + // y축 방향으로 더 많이 이동 + direction = vector.y > 0 ? 'bottom' : 'top' + } + + const line = new fabric.Line( + [ + points.current[0].left, + points.current[0].top, + points.current[0].left + scaledVector.x, + points.current[0].top + scaledVector.y, + ], + { + stroke: 'black', + strokeWidth: 2, + selectable: false, + direction: direction, + }, + ) + + const text = new fabric.Text(length.toString(), { + left: + (points.current[0].left + + points.current[0].left + + scaledVector.x) / + 2, + top: + (points.current[0].top + points.current[0].top + scaledVector.y) / + 2, + fontSize: 15, + originX: 'center', + originY: 'center', + selectable: false, + }) + + // 라인의 끝에 점을 추가합니다. + const endPointCircle = new fabric.Circle({ + radius: 5, + fill: 'transparent', // 원 안을 비웁니다. + stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. + left: points.current[0].left + scaledVector.x, + top: points.current[0].top + scaledVector.y, + originX: 'center', + originY: 'center', + selectable: false, + }) + + canvas?.add(line) + canvas?.add(text) + canvas?.add(endPointCircle) + points.current.forEach((point) => { + canvas?.remove(point) + }) + points.current = [endPointCircle] + } + } + + canvas?.renderAll() + }) + } + + const templateMode = (canvas) => {} + + const textboxMode = (canvas) => { + canvas?.on('mouse:down', function (options) { + const pointer = canvas?.getPointer(options.e) + + const textbox = new fabric.Textbox('텍스트를 입력하세요', { + left: pointer.x, + top: pointer.y, + width: 150, // 텍스트박스의 너비를 설정합니다. + fontSize: 16, // 텍스트의 크기를 설정합니다. + }) + + canvas?.add(textbox) + canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다. + canvas?.renderAll() + }) + } + + return { mode, changeMode } +} + +export const MODE = { + EDIT: 'edit', + TEMPLATE: 'template', + TEXTBOX: 'textbox', +} diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 6c4de51e..8e546d3b 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,135 +1,38 @@ import { useCanvas } from '@/hooks/useCanvas' -import { useEffect, useRef } from 'react' +import { useEffect } from 'react' +import { MODE, useMode } from '@/app/mode' export default function Roof2() { const { canvas } = useCanvas('canvas') - const mode = useRef('') - const points = useRef([]) + + const { mode, changeMode } = useMode() + useEffect(() => { - canvas?.on('mouse:down', function (options) { - const pointer = canvas?.getPointer(options.e) - const circle = new fabric.Circle({ - radius: 5, - fill: 'transparent', // 원 안을 비웁니다. - stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. - left: pointer.x, - top: pointer.y, - originX: 'center', - originY: 'center', - selectable: false, - }) + // canvas가 없는 경우 + if (!canvas) return + // canvas가 있는 경우 + changeMode(canvas, mode) + }, [mode]) - points.current.push(circle) - canvas?.add(circle) - - if (points.current.length === 2) { - const length = Number(prompt('길이를 입력하세요:')) - // length 값이 숫자가 아닌 경우 - if (isNaN(length) || length === 0) { - // 기존에 추가된 circle과 pointer를 제거합니다. - points.current.forEach((point) => { - canvas?.remove(point) - }) - points.current = [] - return - } - - if (length) { - const vector = { - x: points.current[1].left - points.current[0].left, - y: points.current[1].top - points.current[0].top, - } - const slope = Math.abs(vector.y / vector.x) // 기울기 계산 - - let scaledVector - if (slope >= 1) { - // 기울기가 1 이상이면 x축 방향으로 그림 - scaledVector = { - x: 0, - y: vector.y >= 0 ? Number(length) : -Number(length), - } - } else { - // 기울기가 1 미만이면 y축 방향으로 그림 - scaledVector = { - x: vector.x >= 0 ? Number(length) : -Number(length), - y: 0, - } - } - - let direction - if (Math.abs(vector.x) > Math.abs(vector.y)) { - // x축 방향으로 더 많이 이동 - direction = vector.x > 0 ? 'right' : 'left' - } else { - // y축 방향으로 더 많이 이동 - direction = vector.y > 0 ? 'bottom' : 'top' - } - - const line = new fabric.Line( - [ - points.current[0].left, - points.current[0].top, - points.current[0].left + scaledVector.x, - points.current[0].top + scaledVector.y, - ], - { - stroke: 'black', - strokeWidth: 2, - selectable: false, - direction: direction, - }, - ) - - const text = new fabric.Text(length.toString(), { - left: - (points.current[0].left + - points.current[0].left + - scaledVector.x) / - 2, - top: - (points.current[0].top + points.current[0].top + scaledVector.y) / - 2, - fontSize: 15, - originX: 'center', - originY: 'center', - selectable: false, - }) - - // 라인의 끝에 점을 추가합니다. - const endPointCircle = new fabric.Circle({ - radius: 5, - fill: 'transparent', // 원 안을 비웁니다. - stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. - left: points.current[0].left + scaledVector.x, - top: points.current[0].top + scaledVector.y, - originX: 'center', - originY: 'center', - selectable: false, - }) - - canvas?.add(line) - canvas?.add(text) - canvas?.add(endPointCircle) - points.current.forEach((point) => { - canvas?.remove(point) - }) - points.current = [endPointCircle] - } - } - - canvas?.renderAll() - }) - }, [canvas]) return ( <>
- - -
From 2f67885a0d3a4ba088ae9351ce34b97c0e00807a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 15:59:58 +0900 Subject: [PATCH 006/113] =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mode.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/mode.js b/src/app/mode.js index 8911cd18..19bdedbb 100644 --- a/src/app/mode.js +++ b/src/app/mode.js @@ -146,6 +146,7 @@ export function useMode() { const textboxMode = (canvas) => { canvas?.on('mouse:down', function (options) { + if (canvas?.getActiveObject()?.type === 'textbox') return const pointer = canvas?.getPointer(options.e) const textbox = new fabric.Textbox('텍스트를 입력하세요', { @@ -158,6 +159,10 @@ export function useMode() { canvas?.add(textbox) canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다. canvas?.renderAll() + // textbox가 active가 풀린 경우 editing mode로 변경 + textbox?.on('editing:exited', function () { + changeMode(canvas, MODE.EDIT) + }) }) } From 1572c9ca118f3dd9bfc275179458cc57d984b1e0 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 16:08:55 +0900 Subject: [PATCH 007/113] =?UTF-8?q?=EA=B8=B0=EC=A4=80=EC=84=A0=20=EA=B8=8B?= =?UTF-8?q?=EA=B8=B0=EB=AA=A8=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mode.js | 34 ++++++++++++++++++++++++++++------ src/components/Roof2.jsx | 12 +++++++++--- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/app/mode.js b/src/app/mode.js index 19bdedbb..cccafaf1 100644 --- a/src/app/mode.js +++ b/src/app/mode.js @@ -1,11 +1,21 @@ import { useRef, useState } from 'react' +export const MODE = { + DRAW_LINE: 'drawLine', // 기준선 긋기모드 + EDIT: 'edit', + TEMPLATE: 'template', + TEXTBOX: 'textbox', +} + export function useMode() { const [mode, setMode] = useState(MODE.EDIT) const points = useRef([]) const addEvent = (canvas, mode) => { switch (mode) { + case 'drawLine': + drawLineMode(canvas) + break case 'edit': editMode(canvas) break @@ -166,11 +176,23 @@ export function useMode() { }) } + const drawLineMode = (canvas) => { + canvas?.on('mouse:down', function (options) { + const pointer = canvas?.getPointer(options.e) + + const line = new fabric.Line( + [pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다. + { + stroke: 'black', + strokeWidth: 2, + selectable: false, + }, + ) + + canvas?.add(line) + canvas?.renderAll() + }) + } + return { mode, changeMode } } - -export const MODE = { - EDIT: 'edit', - TEMPLATE: 'template', - TEXTBOX: 'textbox', -} diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 8e546d3b..1bb89287 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -17,23 +17,29 @@ export default function Roof2() { return ( <>
+
From c3162e80b4981c046ab0c5f94835286388e73c0c Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 16:58:06 +0900 Subject: [PATCH 008/113] =?UTF-8?q?=EC=82=AC=EA=B0=81=ED=98=95=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=AA=A8=EB=93=9C=20=EC=B6=94=EA=B0=80,=20redo,=20?= =?UTF-8?q?undo=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mode.js | 45 ++++++++++++++++++++++++++++++++++++++++ src/components/Roof2.jsx | 20 +++++++++++++++++- src/hooks/useCanvas.js | 12 +++++++---- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/src/app/mode.js b/src/app/mode.js index cccafaf1..6c8f7239 100644 --- a/src/app/mode.js +++ b/src/app/mode.js @@ -5,6 +5,7 @@ export const MODE = { EDIT: 'edit', TEMPLATE: 'template', TEXTBOX: 'textbox', + DRAW_RECT: 'drawRect', } export function useMode() { @@ -25,6 +26,9 @@ export function useMode() { case 'textbox': textboxMode(canvas) break + case 'drawRect': + drawRectMode(canvas) + break } } @@ -194,5 +198,46 @@ export function useMode() { }) } + const drawRectMode = (canvas) => { + let rect, isDown, origX, origY + canvas.on('mouse:down', function (o) { + isDown = true + const pointer = canvas.getPointer(o.e) + origX = pointer.x + origY = pointer.y + rect = new fabric.Rect({ + left: origX, + top: origY, + originX: 'left', + originY: 'top', + width: pointer.x - origX, + height: pointer.y - origY, + angle: 0, + fill: 'rgba(255,0,0,0.5)', + transparentCorners: false, + }) + canvas.add(rect) + }) + + canvas.on('mouse:move', function (o) { + if (!isDown) return + const pointer = canvas.getPointer(o.e) + if (origX > pointer.x) { + rect.set({ left: Math.abs(pointer.x) }) + } + if (origY > pointer.y) { + rect.set({ top: Math.abs(pointer.y) }) + } + + rect.set({ width: Math.abs(origX - pointer.x) }) + rect.set({ height: Math.abs(origY - pointer.y) }) + canvas.renderAll() + }) + + canvas.on('mouse:up', function (o) { + isDown = false + }) + } + return { mode, changeMode } } diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 1bb89287..4f6329f7 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -3,7 +3,7 @@ import { useEffect } from 'react' import { MODE, useMode } from '@/app/mode' export default function Roof2() { - const { canvas } = useCanvas('canvas') + const { canvas, handleRedo, handleUndo } = useCanvas('canvas') const { mode, changeMode } = useMode() @@ -41,6 +41,24 @@ export default function Roof2() { > 텍스트박스 모드 + + +
{ if (canvas) { initialize() + canvas?.on('object:added', onChange) + canvas?.on('object:modified', onChange) + canvas?.on('object:removed', onChange) canvas?.on('mouse:move', drawMouseLines) canvas?.on('mouse:out', removeMouseLines) } @@ -210,15 +213,16 @@ export function useCanvas(id) { */ const handleUndo = () => { if (canvas) { - if (canvas._objects.length > 0) { - const poppedObject = canvas._objects.pop() + if (canvas?._objects.length > 0) { + const poppedObject = canvas?._objects.pop() + setHistory((prev) => { if (prev === undefined) { return poppedObject ? [poppedObject] : [] } return poppedObject ? [...prev, poppedObject] : prev }) - canvas.renderAll() + canvas?.renderAll() } } } @@ -227,7 +231,7 @@ export function useCanvas(id) { if (canvas && history) { if (history.length > 0) { setIsLocked(true) - canvas.add(history[history.length - 1]) + canvas?.add(history[history.length - 1]) const newHistory = history.slice(0, -1) setHistory(newHistory) } From 75368cc645d912f91e6d3a7e0ad61d4a9a6b7bdc Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 17:28:25 +0900 Subject: [PATCH 009/113] =?UTF-8?q?=ED=85=9C=ED=94=8C=EB=A6=BF=20=EB=AA=A8?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/mode.js | 34 ++++++++++++++++++++++++++++++++-- src/components/Roof2.jsx | 10 ++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/app/mode.js b/src/app/mode.js index 6c8f7239..b8a56d60 100644 --- a/src/app/mode.js +++ b/src/app/mode.js @@ -11,6 +11,8 @@ export const MODE = { export function useMode() { const [mode, setMode] = useState(MODE.EDIT) const points = useRef([]) + const historyPoints = useRef([]) + const lines = useRef([]) const addEvent = (canvas, mode) => { switch (mode) { @@ -54,6 +56,7 @@ export function useMode() { selectable: false, }) + historyPoints.current.push(circle) points.current.push(circle) canvas?.add(circle) @@ -65,6 +68,7 @@ export function useMode() { points.current.forEach((point) => { canvas?.remove(point) }) + historyPoints.current.pop() points.current = [] return } @@ -145,6 +149,9 @@ export function useMode() { canvas?.add(line) canvas?.add(text) canvas?.add(endPointCircle) + + historyPoints.current.push(endPointCircle) + points.current.forEach((point) => { canvas?.remove(point) }) @@ -156,7 +163,29 @@ export function useMode() { }) } - const templateMode = (canvas) => {} + const templateMode = (canvas) => { + changeMode(canvas, MODE.EDIT) + + if (historyPoints.current.length >= 4) { + const firstPoint = historyPoints.current[0] + const lastPoint = historyPoints.current[historyPoints.current.length - 1] + + const line = new fabric.Line( + [firstPoint.left, firstPoint.top, lastPoint.left, lastPoint.top], + { + stroke: 'black', + strokeWidth: 2, + selectable: false, + }, + ) + historyPoints.current.forEach((point) => { + canvas?.remove(point) + }) + historyPoints.current = [] + canvas?.add(line) + canvas?.renderAll() + } + } const textboxMode = (canvas) => { canvas?.on('mouse:down', function (options) { @@ -213,7 +242,8 @@ export function useMode() { width: pointer.x - origX, height: pointer.y - origY, angle: 0, - fill: 'rgba(255,0,0,0.5)', + fill: 'transparent', + stroke: 'black', transparentCorners: false, }) canvas.add(rect) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 4f6329f7..870c83f2 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -3,7 +3,7 @@ import { useEffect } from 'react' import { MODE, useMode } from '@/app/mode' export default function Roof2() { - const { canvas, handleRedo, handleUndo } = useCanvas('canvas') + const { canvas, handleRedo, handleUndo, handleClear } = useCanvas('canvas') const { mode, changeMode } = useMode() @@ -12,7 +12,7 @@ export default function Roof2() { if (!canvas) return // canvas가 있는 경우 changeMode(canvas, mode) - }, [mode]) + }, [mode, canvas]) return ( <> @@ -59,6 +59,12 @@ export default function Roof2() { > Redo +
Date: Mon, 24 Jun 2024 19:14:49 +0900 Subject: [PATCH 010/113] =?UTF-8?q?=ED=85=9C=ED=94=8C=EB=A6=BF=EB=AA=A8?= =?UTF-8?q?=EB=93=9C=20=EC=84=A0=ED=83=9D=EC=8B=9C=20=EA=B8=B0=EC=A1=B4=20?= =?UTF-8?q?line=20=EC=A0=9C=EA=B1=B0=20=ED=9B=84=20polygon=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 24 ++--- src/{app/mode.js => hooks/useMode.js} | 147 ++++++++++++++++++-------- 2 files changed, 117 insertions(+), 54 deletions(-) rename src/{app/mode.js => hooks/useMode.js} (68%) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 870c83f2..8052f75e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,11 +1,11 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEffect } from 'react' -import { MODE, useMode } from '@/app/mode' +import { UseMode, useMode } from '@/hooks/useMode' export default function Roof2() { const { canvas, handleRedo, handleUndo, handleClear } = useCanvas('canvas') - const { mode, changeMode } = useMode() + const { mode, changeMode, setCanvas } = useMode() useEffect(() => { // canvas가 없는 경우 @@ -18,32 +18,32 @@ export default function Roof2() { <>
diff --git a/src/app/mode.js b/src/hooks/useMode.js similarity index 68% rename from src/app/mode.js rename to src/hooks/useMode.js index b8a56d60..36032eef 100644 --- a/src/app/mode.js +++ b/src/hooks/useMode.js @@ -1,6 +1,6 @@ import { useRef, useState } from 'react' -export const MODE = { +export const UseMode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 EDIT: 'edit', TEMPLATE: 'template', @@ -9,27 +9,28 @@ export const MODE = { } export function useMode() { - const [mode, setMode] = useState(MODE.EDIT) + const [mode, setMode] = useState(UseMode.EDIT) const points = useRef([]) const historyPoints = useRef([]) - const lines = useRef([]) + const historyLines = useRef([]) + const [canvas, setCanvas] = useState(null) - const addEvent = (canvas, mode) => { + const addEvent = (mode) => { switch (mode) { case 'drawLine': - drawLineMode(canvas) + drawLineMode() break case 'edit': - editMode(canvas) + editMode() break case 'template': - templateMode(canvas) + templateMode() break case 'textbox': - textboxMode(canvas) + textboxMode() break case 'drawRect': - drawRectMode(canvas) + drawRectMode() break } } @@ -38,15 +39,15 @@ export function useMode() { setMode(mode) // mode변경 시 이전 이벤트 제거 canvas?.off('mouse:down') - - addEvent(canvas, mode) + setCanvas(canvas) + addEvent(mode) } - const editMode = (canvas) => { + const editMode = () => { canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) const circle = new fabric.Circle({ - radius: 5, + radius: 1, fill: 'transparent', // 원 안을 비웁니다. stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. left: pointer.x, @@ -95,15 +96,6 @@ export function useMode() { } } - let direction - if (Math.abs(vector.x) > Math.abs(vector.y)) { - // x축 방향으로 더 많이 이동 - direction = vector.x > 0 ? 'right' : 'left' - } else { - // y축 방향으로 더 많이 이동 - direction = vector.y > 0 ? 'bottom' : 'top' - } - const line = new fabric.Line( [ points.current[0].left, @@ -115,10 +107,12 @@ export function useMode() { stroke: 'black', strokeWidth: 2, selectable: false, - direction: direction, + direction: getDirection(points.current[0], points.current[1]), }, ) + historyLines.current.push(line) + console.log(line) const text = new fabric.Text(length.toString(), { left: (points.current[0].left + @@ -136,7 +130,7 @@ export function useMode() { // 라인의 끝에 점을 추가합니다. const endPointCircle = new fabric.Circle({ - radius: 5, + radius: 1, fill: 'transparent', // 원 안을 비웁니다. stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. left: points.current[0].left + scaledVector.x, @@ -146,6 +140,8 @@ export function useMode() { selectable: false, }) + console.log(endPointCircle) + canvas?.add(line) canvas?.add(text) canvas?.add(endPointCircle) @@ -163,31 +159,23 @@ export function useMode() { }) } - const templateMode = (canvas) => { - changeMode(canvas, MODE.EDIT) + const templateMode = () => { + changeMode(canvas, UseMode.EDIT) if (historyPoints.current.length >= 4) { const firstPoint = historyPoints.current[0] const lastPoint = historyPoints.current[historyPoints.current.length - 1] - - const line = new fabric.Line( - [firstPoint.left, firstPoint.top, lastPoint.left, lastPoint.top], - { - stroke: 'black', - strokeWidth: 2, - selectable: false, - }, - ) historyPoints.current.forEach((point) => { canvas?.remove(point) }) + drawLineWithLength(lastPoint, firstPoint) + points.current = [] historyPoints.current = [] - canvas?.add(line) - canvas?.renderAll() + makePolygon() } } - const textboxMode = (canvas) => { + const textboxMode = () => { canvas?.on('mouse:down', function (options) { if (canvas?.getActiveObject()?.type === 'textbox') return const pointer = canvas?.getPointer(options.e) @@ -204,12 +192,12 @@ export function useMode() { canvas?.renderAll() // textbox가 active가 풀린 경우 editing mode로 변경 textbox?.on('editing:exited', function () { - changeMode(canvas, MODE.EDIT) + changeMode(canvas, UseMode.EDIT) }) }) } - const drawLineMode = (canvas) => { + const drawLineMode = () => { canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) @@ -227,7 +215,7 @@ export function useMode() { }) } - const drawRectMode = (canvas) => { + const drawRectMode = () => { let rect, isDown, origX, origY canvas.on('mouse:down', function (o) { isDown = true @@ -269,5 +257,80 @@ export function useMode() { }) } - return { mode, changeMode } + /** + * 두 점 사이의 방향을 반환합니다. + */ + const getDirection = (a, b) => { + const vector = { + x: b.left - a.left, + y: b.top - a.top, + } + + if (Math.abs(vector.x) > Math.abs(vector.y)) { + // x축 방향으로 더 많이 이동 + return vector.x > 0 ? 'right' : 'left' + } else { + // y축 방향으로 더 많이 이동 + return vector.y > 0 ? 'bottom' : 'top' + } + } + + /** + * 두 점을 연결하는 선과 길이를 그립니다. + */ + const drawLineWithLength = (a, b) => { + const vector = { + x: b.left - a.left, + y: b.top - a.top, + } + const line = new fabric.Line([a.left, a.top, b.left, b.top], { + stroke: 'black', + strokeWidth: 2, + selectable: false, + direction: getDirection(a, b), + }) + historyLines.current.push(line) + + const text = new fabric.Text( + Math.round(Math.sqrt(vector.x ** 2 + vector.y ** 2)).toString(), + { + left: (a.left + b.left) / 2, + top: (a.top + b.top) / 2, + fontSize: 15, + originX: 'center', + originY: 'center', + selectable: false, + }, + ) + + canvas?.add(line) + canvas?.add(text) + canvas?.renderAll() + } + + const makePolygon = () => { + // 캔버스에서 모든 라인 객체를 찾습니다. + const lines = historyLines.current + + // 각 라인의 시작점과 끝점을 사용하여 다각형의 점 배열을 생성합니다. + const points = lines.map((line) => ({ x: line.x1, y: line.y1 })) + + // 모든 라인 객체를 캔버스에서 제거합니다. + lines.forEach((line) => canvas.remove(line)) + + // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다. + const polygon = new fabric.Polygon(points, { + stroke: 'black', + fill: 'transparent', + selectable: false, + }) + + // 새로운 다각형 객체를 캔버스에 추가합니다. + canvas.add(polygon) + + // 캔버스를 다시 그립니다. + canvas.renderAll() + } + + return { mode, changeMode, setCanvas } } From 1898adc005066fc3704757c26fa352860814eb83 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 19:16:34 +0900 Subject: [PATCH 011/113] =?UTF-8?q?historyLine=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 36032eef..9ee3e128 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -311,6 +311,7 @@ export function useMode() { const makePolygon = () => { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = historyLines.current + historyLines.current = [] // 각 라인의 시작점과 끝점을 사용하여 다각형의 점 배열을 생성합니다. const points = lines.map((line) => ({ x: line.x1, y: line.y1 })) From 0acf11539676b030732856dd939dca86e321455f Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 20:05:26 +0900 Subject: [PATCH 012/113] =?UTF-8?q?=EC=82=B4=EC=A7=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 34 +++++++++++++++++----------------- src/hooks/useCanvas.js | 9 --------- src/hooks/useMode.js | 28 ++++++++++++++++++---------- 3 files changed, 35 insertions(+), 36 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 8052f75e..f291409a 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,49 +1,49 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEffect } from 'react' -import { UseMode, useMode } from '@/hooks/useMode' +import { Mode, UseMode, useMode } from '@/hooks/useMode' export default function Roof2() { - const { canvas, handleRedo, handleUndo, handleClear } = useCanvas('canvas') + const { canvas, handleRedo, handleUndo } = useCanvas('canvas') - const { mode, changeMode, setCanvas } = useMode() + const { mode, changeMode, setCanvas, handleClear } = useMode() useEffect(() => { - // canvas가 없는 경우 - if (!canvas) return - // canvas가 있는 경우 + if (!canvas) { + return + } changeMode(canvas, mode) - }, [mode, canvas]) + }, [canvas, mode]) return ( <>
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 627096d5..4864cfbd 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -238,14 +238,6 @@ export function useCanvas(id) { } } - /** - * 해당 캔버스를 비운다. - */ - const handleClear = () => { - canvas?.clear() - initialize() - } - /** * 선택한 도형을 복사한다. */ @@ -506,7 +498,6 @@ export function useCanvas(id) { addShape, handleUndo, handleRedo, - handleClear, handleCopy, handleDelete, handleSave, diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 9ee3e128..8681b8f7 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1,6 +1,6 @@ import { useRef, useState } from 'react' -export const UseMode = { +export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 EDIT: 'edit', TEMPLATE: 'template', @@ -9,13 +9,13 @@ export const UseMode = { } export function useMode() { - const [mode, setMode] = useState(UseMode.EDIT) + const [mode, setMode] = useState(Mode.EDIT) const points = useRef([]) const historyPoints = useRef([]) const historyLines = useRef([]) const [canvas, setCanvas] = useState(null) - const addEvent = (mode) => { + const addEvent = (mode = Mode.EDIT) => { switch (mode) { case 'drawLine': drawLineMode() @@ -35,11 +35,11 @@ export function useMode() { } } - const changeMode = (canvas, mode) => { + const changeMode = (canvas, mode = Mode.EDIT) => { setMode(mode) // mode변경 시 이전 이벤트 제거 - canvas?.off('mouse:down') setCanvas(canvas) + canvas?.off('mouse:down') addEvent(mode) } @@ -112,7 +112,6 @@ export function useMode() { ) historyLines.current.push(line) - console.log(line) const text = new fabric.Text(length.toString(), { left: (points.current[0].left + @@ -140,8 +139,6 @@ export function useMode() { selectable: false, }) - console.log(endPointCircle) - canvas?.add(line) canvas?.add(text) canvas?.add(endPointCircle) @@ -160,7 +157,7 @@ export function useMode() { } const templateMode = () => { - changeMode(canvas, UseMode.EDIT) + changeMode(canvas, Mode.EDIT) if (historyPoints.current.length >= 4) { const firstPoint = historyPoints.current[0] @@ -277,6 +274,7 @@ export function useMode() { /** * 두 점을 연결하는 선과 길이를 그립니다. + * a : 시작점, b : 끝점 */ const drawLineWithLength = (a, b) => { const vector = { @@ -333,5 +331,15 @@ export function useMode() { canvas.renderAll() } - return { mode, changeMode, setCanvas } + /** + * 해당 캔버스를 비운다. + */ + const handleClear = () => { + canvas?.clear() + points.current = [] + historyPoints.current = [] + historyLines.current = [] + } + + return { mode, changeMode, setCanvas, handleClear } } From 098fa9dc1f5f9f3b753915dbfc1dd897788d40ec Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 24 Jun 2024 20:11:40 +0900 Subject: [PATCH 013/113] =?UTF-8?q?default=EA=B0=92=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 102 ++++++++++++++++++++------------------- src/hooks/useMode.js | 6 +-- 2 files changed, 55 insertions(+), 53 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index f291409a..eac12568 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -16,56 +16,58 @@ export default function Roof2() { return ( <> -
- - - - - - - - -
+ {canvas && ( +
+ + + + + + + + +
+ )}
{ + const addEvent = (mode) => { switch (mode) { case 'drawLine': drawLineMode() @@ -35,7 +35,7 @@ export function useMode() { } } - const changeMode = (canvas, mode = Mode.EDIT) => { + const changeMode = (canvas, mode) => { setMode(mode) // mode변경 시 이전 이벤트 제거 setCanvas(canvas) From 328875c6921149a30c7e3f04fa2074d6091e1230 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 25 Jun 2024 11:14:20 +0900 Subject: [PATCH 014/113] =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index e7cf1a01..7f6d5ec9 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -189,7 +189,7 @@ export function useMode() { canvas?.renderAll() // textbox가 active가 풀린 경우 editing mode로 변경 textbox?.on('editing:exited', function () { - changeMode(canvas, UseMode.EDIT) + changeMode(canvas, Mode.EDIT) }) }) } From f73f21b7c8397c560500a045b2c79ff52f068146 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 25 Jun 2024 11:21:43 +0900 Subject: [PATCH 015/113] =?UTF-8?q?=EC=A4=91=EB=B3=B5=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index eac12568..a13164b2 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,6 +1,6 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEffect } from 'react' -import { Mode, UseMode, useMode } from '@/hooks/useMode' +import { Mode, useMode } from '@/hooks/useMode' export default function Roof2() { const { canvas, handleRedo, handleUndo } = useCanvas('canvas') From bd10d3f2890f718ff8c9a231ab9e5b3619fa1f64 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 26 Jun 2024 16:42:51 +0900 Subject: [PATCH 016/113] =?UTF-8?q?=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 106 ++++++++++++++++++- src/components/fabric/QLine.js | 36 +++++++ src/components/fabric/QPolygon.js | 42 ++++++++ src/components/fabric/QRect.js | 58 ++++++++++ src/hooks/useMode.js | 169 +++++++++++++++++++++++------- 5 files changed, 375 insertions(+), 36 deletions(-) create mode 100644 src/components/fabric/QLine.js create mode 100644 src/components/fabric/QPolygon.js create mode 100644 src/components/fabric/QRect.js diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index a13164b2..9c06cff2 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,11 +1,22 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEffect } from 'react' import { Mode, useMode } from '@/hooks/useMode' +import QRect from '@/components/fabric/QRect' +import QLine from '@/components/fabric/QLine' +import QPolygon from '@/components/fabric/QPolygon' export default function Roof2() { const { canvas, handleRedo, handleUndo } = useCanvas('canvas') - const { mode, changeMode, setCanvas, handleClear } = useMode() + const { + mode, + changeMode, + handleClear, + fillCellInPolygon, + zoomIn, + zoomOut, + zoom, + } = useMode() useEffect(() => { if (!canvas) { @@ -14,6 +25,62 @@ export default function Roof2() { 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, + isLengthText: true, // 이 속성이 true로 설정되면, 사각형의 각 선분의 길이를 표시하는 텍스트가 생성됩니다. + selectable: false, + }) + + canvas?.add(rect) + } + } + + const makeLine = () => { + if (canvas) { + const line = new QLine([50, 50, 200, 200], { + stroke: 'black', + strokeWidth: 2, + isLengthText: true, // 이 속성이 true로 설정되면, 선분의 길이를 표시하는 텍스트가 생성됩니다. + selectable: false, + }) + + canvas?.add(line) + } + } + + const makePolygon = () => { + if (canvas) { + const polygon = new QPolygon( + [ + { x: 100, y: 100 }, + { x: 200, y: 200 }, + { x: 200, y: 300 }, + { x: 100, y: 300 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + isLengthText: true, // 이 속성이 true로 설정되면, 다각형의 각 변의 길이를 표시하는 텍스트가 생성됩니다. + selectable: false, + }, + ) + + canvas?.add(polygon) + + setTimeout(() => { + console.log(canvas?.getObjects()) + }, 1000) + } + } + return ( <> {canvas && ( @@ -66,6 +133,43 @@ export default function Roof2() { > clear + + + + 현재 줌 : {zoom}% + + +
)} diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js new file mode 100644 index 00000000..4fa81751 --- /dev/null +++ b/src/components/fabric/QLine.js @@ -0,0 +1,36 @@ +export default class QLine extends fabric.Line { + length + constructor(points, option) { + super(points, option) + + this.on('added', () => { + if (this.isLengthText) { + this.addLengthText() + } + }) + } + + addLengthText() { + const dx = this.x2 - this.x1 + const dy = this.y2 - this.y1 + const length = Math.sqrt(dx * dx + dy * dy) + + this.length = length.toFixed(0) + + const text = new fabric.Text(this.length, { + left: (this.x1 + this.x2) / 2, + top: (this.y1 + this.y2) / 2, + fontSize: 16, + selectable: false, + }) + + const group = new fabric.Group([this, text], { + selectable: false, + type: 'QLine', + }) + + this.canvas.add(group) + this.canvas.renderAll() + this.canvas.remove(this) + } +} diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js new file mode 100644 index 00000000..c747e04b --- /dev/null +++ b/src/components/fabric/QPolygon.js @@ -0,0 +1,42 @@ +export default class QPolygon extends fabric.Polygon { + constructor(points, option) { + super(points, option) + + this.on('added', () => { + if (this.isLengthText) { + this.addLengthText() + } + }) + } + + addLengthText() { + const groupItems = [this] + + for (let i = 0; i < this.points.length; i++) { + const start = this.points[i] + const end = this.points[(i + 1) % this.points.length] + + const dx = end.x - start.x + const dy = end.y - start.y + const length = Math.sqrt(dx * dx + dy * dy) + + const text = new fabric.Text(length.toFixed(0), { + left: (start.x + end.x) / 2, + top: (start.y + end.y) / 2, + fontSize: 16, + selectable: false, + }) + + groupItems.push(text) + } + + const group = new fabric.Group(groupItems, { + selectable: false, + type: 'QPolygon', + }) + + this.canvas.add(group) + this.canvas.renderAll() + this.canvas.remove(this) + } +} diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js new file mode 100644 index 00000000..ceae98f5 --- /dev/null +++ b/src/components/fabric/QRect.js @@ -0,0 +1,58 @@ +export default class QRect extends fabric.Rect { + constructor(options) { + super(options) + + this.on('added', () => { + if (this.isLengthText) { + this.addLengthText() + } + }) + } + + addLengthText() { + const lines = [ + { + start: { x: this.left, y: this.top }, + end: { x: this.left + this.width, y: this.top }, + }, + { + start: { x: this.left + this.width, y: this.top }, + end: { x: this.left + this.width, y: this.top + this.height }, + }, + { + start: { x: this.left + this.width, y: this.top + this.height }, + end: { x: this.left, y: this.top + this.height }, + }, + { + start: { x: this.left, y: this.top + this.height }, + end: { x: this.left, y: this.top }, + }, + ] + + const groupItems = [this] + + lines.forEach((line) => { + const dx = line.end.x - line.start.x + const dy = line.end.y - line.start.y + const length = Math.sqrt(dx * dx + dy * dy) + + const text = new fabric.Text(length.toFixed(0), { + left: (line.start.x + line.end.x) / 2, + top: (line.start.y + line.end.y) / 2, + fontSize: 16, + selectable: false, + }) + + groupItems.push(text) + }) + + const group = new fabric.Group(groupItems, { + selectable: false, + type: 'QRect', + }) + + this.canvas.add(group) + this.canvas.renderAll() + this.canvas.remove(this) + } +} diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 7f6d5ec9..b8421315 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1,4 +1,7 @@ import { useRef, useState } from 'react' +import QLine from '@/components/fabric/QLine' +import QRect from '@/components/fabric/QRect' +import QPolygon from '@/components/fabric/QPolygon' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 @@ -14,6 +17,7 @@ export function useMode() { const historyPoints = useRef([]) const historyLines = useRef([]) const [canvas, setCanvas] = useState(null) + const [zoom, setZoom] = useState(100) const addEvent = (mode) => { switch (mode) { @@ -44,6 +48,38 @@ export function useMode() { } const editMode = () => { + let distanceText = null // 거리를 표시하는 텍스트 객체를 저장할 변수 + canvas?.on('mouse:move', function (options) { + const pointer = canvas?.getPointer(options.e) + + if (historyLines.current.length === 0) return + const direction = getDirection(historyLines.current[0], pointer) + + // 각 선과 마우스 위치 사이의 거리를 계산합니다. + const dx = historyLines.current[0].x1 - pointer.x + const dy = 0 + + const minDistance = Math.sqrt(dx * dx + dy * dy) + + // 거리를 표시하는 텍스트 객체를 생성하거나 업데이트합니다. + if (distanceText) { + distanceText.set({ + left: pointer.x, + top: pointer.y, + text: `${minDistance.toFixed(2)}`, + }) + } else { + distanceText = new fabric.Text(`${minDistance.toFixed(2)}`, { + left: pointer.x, + top: pointer.y, + fontSize: 16, + }) + canvas?.add(distanceText) + } + + // 캔버스를 다시 그립니다. + canvas?.renderAll() + }) canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) const circle = new fabric.Circle({ @@ -96,7 +132,7 @@ export function useMode() { } } - const line = new fabric.Line( + const line = new QLine( [ points.current[0].left, points.current[0].top, @@ -107,26 +143,12 @@ export function useMode() { stroke: 'black', strokeWidth: 2, selectable: false, + isLengthText: true, direction: getDirection(points.current[0], points.current[1]), }, ) historyLines.current.push(line) - const text = new fabric.Text(length.toString(), { - left: - (points.current[0].left + - points.current[0].left + - scaledVector.x) / - 2, - top: - (points.current[0].top + points.current[0].top + scaledVector.y) / - 2, - fontSize: 15, - originX: 'center', - originY: 'center', - selectable: false, - }) - // 라인의 끝에 점을 추가합니다. const endPointCircle = new fabric.Circle({ radius: 1, @@ -140,7 +162,6 @@ export function useMode() { }) canvas?.add(line) - canvas?.add(text) canvas?.add(endPointCircle) historyPoints.current.push(endPointCircle) @@ -198,11 +219,12 @@ export function useMode() { canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) - const line = new fabric.Line( + const line = new QLine( [pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다. { stroke: 'black', strokeWidth: 2, + isLengthText: true, selectable: false, }, ) @@ -219,7 +241,7 @@ export function useMode() { const pointer = canvas.getPointer(o.e) origX = pointer.x origY = pointer.y - rect = new fabric.Rect({ + rect = new QRect({ left: origX, top: origY, originX: 'left', @@ -228,6 +250,7 @@ export function useMode() { height: pointer.y - origY, angle: 0, fill: 'transparent', + isLengthText: true, stroke: 'black', transparentCorners: false, }) @@ -281,7 +304,7 @@ export function useMode() { x: b.left - a.left, y: b.top - a.top, } - const line = new fabric.Line([a.left, a.top, b.left, b.top], { + const line = new QLine([a.left, a.top, b.left, b.top], { stroke: 'black', strokeWidth: 2, selectable: false, @@ -289,20 +312,7 @@ export function useMode() { }) historyLines.current.push(line) - const text = new fabric.Text( - Math.round(Math.sqrt(vector.x ** 2 + vector.y ** 2)).toString(), - { - left: (a.left + b.left) / 2, - top: (a.top + b.top) / 2, - fontSize: 15, - originX: 'center', - originY: 'center', - selectable: false, - }, - ) - canvas?.add(line) - canvas?.add(text) canvas?.renderAll() } @@ -318,9 +328,10 @@ export function useMode() { lines.forEach((line) => canvas.remove(line)) // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다. - const polygon = new fabric.Polygon(points, { + const polygon = new QPolygon(points, { stroke: 'black', fill: 'transparent', + isLengthText: true, selectable: false, }) @@ -341,5 +352,93 @@ export function useMode() { historyLines.current = [] } - return { mode, changeMode, setCanvas, handleClear } + const fillCellInPolygon = ( + polygon = null, + cell = { width: 50, height: 100 }, + padding = 20, + ) => { + if (!polygon) { + polygon = canvas?.getObjects().find((obj) => obj.type === 'polygon') + if (!polygon) { + alert('다각형을 먼저 그려주세요') + return + } + } + const polygonWidth = polygon.width - 2 * padding + const polygonHeight = polygon.height - 2 * padding + + const numRectanglesWidth = Math.floor(polygonWidth / (cell.width + padding)) + const numRectanglesHeight = Math.floor( + polygonHeight / (cell.height + padding), + ) + + const points = polygon.get('points') // 다각형의 각 꼭지점을 가져옵니다. + const lines = [] + + for (let i = 0; i < points.length; i++) { + const start = points[i] + const end = points[(i + 1) % points.length] // 다각형이 닫히도록 마지막 점과 첫번째 점을 연결합니다. + + const line = new fabric.Line([start.x, start.y, end.x, end.y], { + stroke: 'black', + selectable: false, + }) + + lines.push(line) + } + + for (let i = 0; i < numRectanglesWidth; i++) { + for (let j = 0; j < numRectanglesHeight; j++) { + const rect = new fabric.Rect({ + left: i * (cell.width + padding) + polygon.left + padding, + top: j * (cell.height + padding) + polygon.top + padding, + width: cell.width, + height: cell.height, + fill: 'transparent', + stroke: 'red', + }) + + // 사각형의 각 꼭지점을 생성합니다. + const rectPoints = [ + new fabric.Point(rect.left, rect.top), + new fabric.Point(rect.left + rect.width, rect.top), + new fabric.Point(rect.left, rect.top + rect.height), + new fabric.Point(rect.left + rect.width, rect.top + rect.height), + ] + + // 모든 꼭지점이 다각형 내부에 있는지 확인합니다. + const isInside = rectPoints.every((rectPoint) => + polygon.containsPoint(rectPoint), + ) + + // 모든 꼭지점이 다각형 내부에 있을 경우에만 사각형을 그립니다. + if (isInside) { + canvas.add(rect) + } + } + } + canvas.renderAll() + } + + const zoomIn = () => { + canvas?.setZoom(canvas.getZoom() + 0.1) + + setZoom(Math.round(zoom + 10)) + } + + const zoomOut = () => { + canvas?.setZoom(canvas.getZoom() - 0.1) + setZoom(Math.ceil(zoom - 10)) + } + + return { + mode, + changeMode, + setCanvas, + handleClear, + fillCellInPolygon, + zoomIn, + zoomOut, + zoom, + } } From 1496ea72249d912ec0eb45683174d027df6dfc40 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 26 Jun 2024 17:48:38 +0900 Subject: [PATCH 017/113] =?UTF-8?q?QLine,=20QPolygon,=20QRect=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20-=20=EC=82=AD=EC=A0=9C=20=EB=B0=A9=EB=B2=95?= =?UTF-8?q?=EC=9D=B4=20=EC=82=B4=EC=A7=9D=20=EB=8B=A4=EB=A6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 8 ++++--- src/components/fabric/QLine.js | 35 ++++++++++++++++++++++--------- src/components/fabric/QPolygon.js | 35 ++++++++++++++++++++++--------- src/components/fabric/QRect.js | 34 +++++++++++++++++++++--------- src/hooks/useCanvas.js | 2 +- src/hooks/useMode.js | 28 ++++++++++++++++++------- 6 files changed, 101 insertions(+), 41 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 9c06cff2..55b9c219 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -39,6 +39,8 @@ export default function Roof2() { }) canvas?.add(rect) + + setTimeout(() => rect.delete(), 500) } } @@ -52,6 +54,8 @@ export default function Roof2() { }) canvas?.add(line) + + setTimeout(() => line.delete(), 500) } } @@ -75,9 +79,7 @@ export default function Roof2() { canvas?.add(polygon) - setTimeout(() => { - console.log(canvas?.getObjects()) - }, 1000) + setTimeout(() => polygon.delete(), 500) } } diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 4fa81751..b7e9777c 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -1,16 +1,38 @@ +import { fabric } from 'fabric' export default class QLine extends fabric.Line { length + group + constructor(points, option) { super(points, option) this.on('added', () => { if (this.isLengthText) { - this.addLengthText() + this.#addLengthText() + } else { + this.#makeGroupItem([this]) } }) } - addLengthText() { + delete() { + this.group.canvas.remove(this.group) + } + + #makeGroupItem(groupItems) { + const group = new fabric.Group(groupItems, { + selectable: false, + type: 'QRect', + canvas: this.canvas, + }) + + this.group = group + this.canvas.add(group) + this.canvas.renderAll() + this.canvas.remove(this) + } + + #addLengthText() { const dx = this.x2 - this.x1 const dy = this.y2 - this.y1 const length = Math.sqrt(dx * dx + dy * dy) @@ -24,13 +46,6 @@ export default class QLine extends fabric.Line { selectable: false, }) - const group = new fabric.Group([this, text], { - selectable: false, - type: 'QLine', - }) - - this.canvas.add(group) - this.canvas.renderAll() - this.canvas.remove(this) + this.#makeGroupItem([this, text]) } } diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index c747e04b..efbb2491 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,15 +1,37 @@ +import { fabric } from 'fabric' export default class QPolygon extends fabric.Polygon { + group + constructor(points, option) { super(points, option) this.on('added', () => { if (this.isLengthText) { - this.addLengthText() + this.#addLengthText() + } else { + this.#makeGroupItem([this]) } }) } - addLengthText() { + #makeGroupItem(groupItems) { + const group = new fabric.Group(groupItems, { + selectable: false, + type: 'QRect', + canvas: this.canvas, + }) + + this.group = group + this.canvas.add(group) + this.canvas.renderAll() + this.canvas.remove(this) + } + + delete() { + this.group.canvas.remove(this.group) + } + + #addLengthText() { const groupItems = [this] for (let i = 0; i < this.points.length; i++) { @@ -30,13 +52,6 @@ export default class QPolygon extends fabric.Polygon { groupItems.push(text) } - const group = new fabric.Group(groupItems, { - selectable: false, - type: 'QPolygon', - }) - - this.canvas.add(group) - this.canvas.renderAll() - this.canvas.remove(this) + this.#makeGroupItem(groupItems) } } diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js index ceae98f5..ffb21d57 100644 --- a/src/components/fabric/QRect.js +++ b/src/components/fabric/QRect.js @@ -1,15 +1,36 @@ +import { fabric } from 'fabric' export default class QRect extends fabric.Rect { + group constructor(options) { super(options) this.on('added', () => { if (this.isLengthText) { - this.addLengthText() + this.#addLengthText() + } else { + this.#makeGroupItem([this]) } }) } - addLengthText() { + delete() { + this.group.canvas.remove(this.group) + } + + #makeGroupItem(groupItems) { + const group = new fabric.Group(groupItems, { + selectable: false, + type: 'QRect', + canvas: this.canvas, + }) + + this.group = group + this.canvas.add(group) + this.canvas.renderAll() + this.canvas.remove(this) + } + + #addLengthText() { const lines = [ { start: { x: this.left, y: this.top }, @@ -46,13 +67,6 @@ export default class QRect extends fabric.Rect { groupItems.push(text) }) - const group = new fabric.Group(groupItems, { - selectable: false, - type: 'QRect', - }) - - this.canvas.add(group) - this.canvas.renderAll() - this.canvas.remove(this) + this.#makeGroupItem(groupItems) } } diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 4864cfbd..1fcca833 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -116,7 +116,7 @@ export function useCanvas(id) { const onChange = (e) => { const target = e.target if (target) { - settleDown(target) + // settleDown(target) } if (!isLocked) { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index b8421315..ec9f142b 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -241,7 +241,7 @@ export function useMode() { const pointer = canvas.getPointer(o.e) origX = pointer.x origY = pointer.y - rect = new QRect({ + rect = new fabric.Rect({ left: origX, top: origY, originX: 'left', @@ -250,7 +250,6 @@ export function useMode() { height: pointer.y - origY, angle: 0, fill: 'transparent', - isLengthText: true, stroke: 'black', transparentCorners: false, }) @@ -269,10 +268,25 @@ export function useMode() { rect.set({ width: Math.abs(origX - pointer.x) }) rect.set({ height: Math.abs(origY - pointer.y) }) - canvas.renderAll() }) canvas.on('mouse:up', function (o) { + const pointer = canvas.getPointer(o.e) + const qRect = new QRect({ + left: origX, + top: origY, + originX: 'left', + originY: 'top', + width: pointer.x - origX, + height: pointer.y - origY, + angle: 0, + isLengthText: true, + fill: 'transparent', + stroke: 'black', + transparentCorners: false, + }) + canvas.remove(rect) + canvas.add(qRect) isDown = false }) } @@ -308,6 +322,7 @@ export function useMode() { stroke: 'black', strokeWidth: 2, selectable: false, + isLengthText: true, direction: getDirection(a, b), }) historyLines.current.push(line) @@ -325,7 +340,9 @@ export function useMode() { const points = lines.map((line) => ({ x: line.x1, y: line.y1 })) // 모든 라인 객체를 캔버스에서 제거합니다. - lines.forEach((line) => canvas.remove(line)) + lines.forEach((line) => { + line.delete() + }) // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다. const polygon = new QPolygon(points, { @@ -337,9 +354,6 @@ export function useMode() { // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) - - // 캔버스를 다시 그립니다. - canvas.renderAll() } /** From 9a5343eb76f0a30482e995e552fea0fa78f2be72 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 26 Jun 2024 18:45:51 +0900 Subject: [PATCH 018/113] =?UTF-8?q?=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 13 ++--- src/components/fabric/QLine.js | 2 +- src/components/fabric/QPolygon.js | 53 +++++++++++++++++++- src/components/fabric/QRect.js | 10 +--- src/hooks/useMode.js | 82 +++---------------------------- 5 files changed, 64 insertions(+), 96 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 55b9c219..7218c06b 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -34,7 +34,7 @@ export default function Roof2() { stroke: 'black', width: 400, height: 100, - isLengthText: true, // 이 속성이 true로 설정되면, 사각형의 각 선분의 길이를 표시하는 텍스트가 생성됩니다. + viewLengthText: true, // 이 속성이 true로 설정되면, 사각형의 각 선분의 길이를 표시하는 텍스트가 생성됩니다. selectable: false, }) @@ -49,7 +49,7 @@ export default function Roof2() { const line = new QLine([50, 50, 200, 200], { stroke: 'black', strokeWidth: 2, - isLengthText: true, // 이 속성이 true로 설정되면, 선분의 길이를 표시하는 텍스트가 생성됩니다. + viewLengthText: true, // 이 속성이 true로 설정되면, 선분의 길이를 표시하는 텍스트가 생성됩니다. selectable: false, }) @@ -72,12 +72,13 @@ export default function Roof2() { fill: 'transparent', stroke: 'black', strokeWidth: 2, - isLengthText: true, // 이 속성이 true로 설정되면, 다각형의 각 변의 길이를 표시하는 텍스트가 생성됩니다. + viewLengthText: true, // 이 속성이 true로 설정되면, 다각형의 각 변의 길이를 표시하는 텍스트가 생성됩니다. selectable: false, }, ) canvas?.add(polygon) + console.log(polygon.polygon) setTimeout(() => polygon.delete(), 500) } @@ -135,12 +136,6 @@ export default function Roof2() { > clear - + +
)} From 131d05d93fc322fa260eb39baceaea0e7a73e4e9 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 2 Jul 2024 12:13:23 +0900 Subject: [PATCH 033/113] =?UTF-8?q?=EA=B0=80=EC=9E=A5=20=EC=9E=91=EC=9D=80?= =?UTF-8?q?=20=EC=A0=90=EC=9D=98=20index=20=EA=B5=AC=ED=95=98=EB=8A=94=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80,=20=EC=A0=90=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/util/canvas-util.js | 53 +++++++++++++------------------------ src/components/Roof2.jsx | 4 +-- src/hooks/useCanvas.js | 42 +++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/app/util/canvas-util.js b/src/app/util/canvas-util.js index bb8eaab3..e5272f19 100644 --- a/src/app/util/canvas-util.js +++ b/src/app/util/canvas-util.js @@ -131,43 +131,26 @@ export const distanceBetweenPoints = (point1, point2) => { return Math.sqrt(dx * dx + dy * dy) } -function fillCanvasWithDots(canvas, gap) { - const width = canvas.getWidth() - const height = canvas.getHeight() +/** + * line의 시작점을 찾는 함수 + * @param lines + * @returns {number} + */ +export const getStartIndex = (lines) => { + let smallestIndex = 0 + let smallestX1 = lines[0].x1 + let smallestY1 = lines[0].y1 - for (let x = 0; x < width; x += gap) { - for (let y = 0; y < height; y += gap) { - const circle = new fabric.Circle({ - radius: 1, - fill: 'black', - left: x, - top: y, - selectable: false, - }) - canvas.add(circle) + for (let i = 1; i < arr.length; i++) { + if ( + lines[i].x1 < smallestX1 || + (lines[i].x1 === smallestX1 && lines[i].y1 < smallestY1) + ) { + smallestIndex = i + smallestX1 = lines[i].x1 + smallestY1 = lines[i].y1 } } - canvas.renderAll() -} - -export const setCanvasBackgroundWithDots = (canvas, gap) => { - // Create a new canvas and fill it with dots - const tempCanvas = new fabric.StaticCanvas() - tempCanvas.setDimensions({ - width: canvas.getWidth(), - height: canvas.getHeight(), - }) - fillCanvasWithDots(tempCanvas, gap) - - // Convert the dotted canvas to an image - const dataUrl = tempCanvas.toDataURL({ format: 'png' }) - - // Set the image as the background of the original canvas - fabric.Image.fromURL(dataUrl, function (img) { - canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { - scaleX: canvas.width / img.width, - scaleY: canvas.height / img.height, - }) - }) + return smallestIndex } diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 40f2da7e..9c783a77 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -4,10 +4,10 @@ import { Mode, useMode } from '@/hooks/useMode' import QRect from '@/components/fabric/QRect' import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' -import { setCanvasBackgroundWithDots } from '@/app/util/canvas-util' export default function Roof2() { - const { canvas, handleRedo, handleUndo } = useCanvas('canvas') + const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots } = + useCanvas('canvas') const { mode, diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 1fcca833..2ff40959 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -493,6 +493,47 @@ export function useCanvas(id) { canvas?.renderAll() } + function fillCanvasWithDots(canvas, gap) { + const width = canvas.getWidth() + const height = canvas.getHeight() + + for (let x = 0; x < width; x += gap) { + for (let y = 0; y < height; y += gap) { + const circle = new fabric.Circle({ + radius: 1, + fill: 'black', + left: x, + top: y, + selectable: false, + }) + canvas.add(circle) + } + } + + canvas.renderAll() + } + + const setCanvasBackgroundWithDots = (canvas, gap) => { + // Create a new canvas and fill it with dots + const tempCanvas = new fabric.StaticCanvas() + tempCanvas.setDimensions({ + width: canvas.getWidth(), + height: canvas.getHeight(), + }) + fillCanvasWithDots(tempCanvas, gap) + + // Convert the dotted canvas to an image + const dataUrl = tempCanvas.toDataURL({ format: 'png' }) + + // Set the image as the background of the original canvas + fabric.Image.fromURL(dataUrl, function (img) { + canvas.setBackgroundImage(img, canvas.renderAll.bind(canvas), { + scaleX: canvas.width / img.width, + scaleY: canvas.height / img.height, + }) + }) + } + return { canvas, addShape, @@ -506,5 +547,6 @@ export function useCanvas(id) { attachCustomControlOnPolygon, saveImage, handleFlip, + setCanvasBackgroundWithDots, } } From 2eba4d62792c2d16893bbd96a68246f544ca92bb Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 2 Jul 2024 13:30:43 +0900 Subject: [PATCH 034/113] =?UTF-8?q?=EB=B3=80=EC=88=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/util/canvas-util.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/util/canvas-util.js b/src/app/util/canvas-util.js index e5272f19..2a329e8e 100644 --- a/src/app/util/canvas-util.js +++ b/src/app/util/canvas-util.js @@ -141,7 +141,7 @@ export const getStartIndex = (lines) => { let smallestX1 = lines[0].x1 let smallestY1 = lines[0].y1 - for (let i = 1; i < arr.length; i++) { + for (let i = 1; i < lines.length; i++) { if ( lines[i].x1 < smallestX1 || (lines[i].x1 === smallestX1 && lines[i].y1 < smallestY1) From 364d32e3496bfbb140194127bc24f3a724ba42fc Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 2 Jul 2024 14:33:27 +0900 Subject: [PATCH 035/113] =?UTF-8?q?=EC=93=B0=EC=9E=98=EB=8D=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=97=86=EB=8A=94=20=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 87291181..89cc8b56 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -2,6 +2,7 @@ import { useRef, useState } from 'react' import QLine from '@/components/fabric/QLine' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' +import { getStartIndex, rearrangeArray } from '@/app/util/canvas-util' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 @@ -558,7 +559,6 @@ export function useMode() { } } - console.log(newOuterlines) makePolygon(newOuterlines) } From c102c0592ff06458794d7d9a2519acce16d3153a Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 2 Jul 2024 14:33:54 +0900 Subject: [PATCH 036/113] =?UTF-8?q?=EC=8A=AC=EB=9D=BC=EC=9D=B4=EB=8D=94=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20=ED=8E=98=EC=9D=B4=EC=A7=80=EC=97=90=20=EC=98=88?= =?UTF-8?q?=EC=A0=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 253 ++++++++++++++++++------------ src/components/ui/RangeSlider.jsx | 25 +++ 2 files changed, 174 insertions(+), 104 deletions(-) create mode 100644 src/components/ui/RangeSlider.jsx diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 9c783a77..98e3321a 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,14 +1,22 @@ import { useCanvas } from '@/hooks/useCanvas' -import { useEffect } from 'react' +import { useEffect, useState } from 'react' import { Mode, useMode } from '@/hooks/useMode' import QRect from '@/components/fabric/QRect' import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' +import RangeSlider from './ui/RangeSlider' export default function Roof2() { const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots } = useCanvas('canvas') + //canvas 가로 사이즈 + const [verticalSize, setVerticalSize] = useState(0) + //canvas 세로 사이즈 + const [horizontalSize, setHorizontalSize] = useState(0) + // 글자크기 + const [fontSize, setFontSize] = useState(0) + const { mode, changeMode, @@ -76,109 +84,146 @@ export default function Roof2() { return ( <> {canvas && ( -
- - - - - - - - - - - - 현재 줌 : {zoom}% - - - - - -
+ <> +
+ + + + + + + + + + + + 현재 줌 : {zoom}% + + + + + +
+
+
+ +
+
+ +
+
+ +
+
+ )}
{} }, +) { + const { title, initValue, onchange } = props + + const handleChange = (e) => { + console.log(e.target.value) + onchange(e.target.value) + } + + return ( + <> + + + + ) +} From 64dab76a6a2825c16495ac7cd8fe2c5a00890dd8 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 2 Jul 2024 14:34:09 +0900 Subject: [PATCH 037/113] =?UTF-8?q?=EB=B0=B0=EC=97=B4=20=EC=9E=AC=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=ED=95=A8=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/util/canvas-util.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/app/util/canvas-util.js b/src/app/util/canvas-util.js index 2a329e8e..cd32d081 100644 --- a/src/app/util/canvas-util.js +++ b/src/app/util/canvas-util.js @@ -154,3 +154,26 @@ export const getStartIndex = (lines) => { return smallestIndex } + +/** + * 이 함수는 두 개의 매개변수를 받습니다: array와 index. + * array는 재배열할 대상 배열입니다. + * index는 재배열의 기준이 될 배열 내의 위치입니다. + * 함수는 먼저 index 위치부터 배열의 마지막 요소까지를 추출합니다(fromIndexToEnd). + * 그 다음, 배열의 처음부터 index 위치까지의 요소를 추출합니다(fromStartToIndex). + * 마지막으로, fromIndexToEnd와 fromStartToIndex 두 부분을 concat 메소드를 이용해 합칩니다. + * 따라서, 이 함수는 주어진 index를 기준으로 배열을 두 부분으로 나누고, index부터 시작하는 부분을 앞에 두고, 그 뒤에 index 이전의 부분을 이어붙여 새로운 배열을 생성합니다. 이는 배열의 회전(rotating) 연산을 수행하는 것과 유사합니다. + * @param array 재배열할 대상 배열 + * @param index 재배열 기준이 될 배열 내의 인덱스 + * @returns {*} 새로 재배열된 배열 + */ +export const rearrangeArray = (array, index) => { + // 배열의 특정 인덱스부터 마지막 요소까지를 가져옵니다. + const fromIndexToEnd = array.slice(index) + + // 배열의 처음부터 특정 인덱스까지의 요소를 가져옵니다. + const fromStartToIndex = array.slice(0, index) + + // 두 부분을 concat 메소드를 이용해 합칩니다. + return fromIndexToEnd.concat(fromStartToIndex) +} From d7f32a5f14836414923290d1c6272c728c467507 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 2 Jul 2024 16:22:04 +0900 Subject: [PATCH 038/113] =?UTF-8?q?RangeSlider=20props=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RangeSlider props 추가 --- src/components/Roof2.jsx | 33 +++++++++++++++++++------------ src/components/ui/RangeSlider.jsx | 7 +++++-- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 98e3321a..eb3cd57e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -11,9 +11,9 @@ export default function Roof2() { useCanvas('canvas') //canvas 가로 사이즈 - const [verticalSize, setVerticalSize] = useState(0) + const [verticalSize, setVerticalSize] = useState(1000) //canvas 세로 사이즈 - const [horizontalSize, setHorizontalSize] = useState(0) + const [horizontalSize, setHorizontalSize] = useState(1000) // 글자크기 const [fontSize, setFontSize] = useState(0) @@ -81,6 +81,18 @@ export default function Roof2() { } } + const canvasSizeMode = () => { + if(canvas) { + canvas.setWidth(parseInt(verticalSize)); + canvas.setHeight(parseInt(horizontalSize)); + canvas.renderAll(); + } + } + + useEffect(() => { + canvasSizeMode() + }, [verticalSize, horizontalSize]) + return ( <> {canvas && ( @@ -205,6 +217,8 @@ export default function Roof2() {
@@ -212,6 +226,8 @@ export default function Roof2() {
@@ -225,17 +241,8 @@ export default function Roof2() {
)} - -
- +
+
) diff --git a/src/components/ui/RangeSlider.jsx b/src/components/ui/RangeSlider.jsx index 94f3bb57..96f60d2c 100644 --- a/src/components/ui/RangeSlider.jsx +++ b/src/components/ui/RangeSlider.jsx @@ -1,7 +1,7 @@ export default function RangeSlider( - props = { title: 'default title', initValue: 0, onchange: () => {} }, + props = { title: 'default title', initValue: 0, onchange: () => {}, step: 1, min:0, max:100}, ) { - const { title, initValue, onchange } = props + const { title, initValue, onchange, step, min, max } = props const handleChange = (e) => { console.log(e.target.value) @@ -17,6 +17,9 @@ export default function RangeSlider( id="default-range" type="range" value={initValue} + min={min} + max={max} + step={step} className="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer" onChange={handleChange} /> From cea2ecf9ef17e20420b8fffb19898fb1c4a493c7 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 2 Jul 2024 16:27:44 +0900 Subject: [PATCH 039/113] =?UTF-8?q?console.log=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/RangeSlider.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ui/RangeSlider.jsx b/src/components/ui/RangeSlider.jsx index 96f60d2c..2250c6d9 100644 --- a/src/components/ui/RangeSlider.jsx +++ b/src/components/ui/RangeSlider.jsx @@ -4,7 +4,7 @@ export default function RangeSlider( const { title, initValue, onchange, step, min, max } = props const handleChange = (e) => { - console.log(e.target.value) + // console.log(e.target.value) onchange(e.target.value) } From 56b168385998ad6a5472feabea0b5e2b17649ab2 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 2 Jul 2024 16:33:07 +0900 Subject: [PATCH 040/113] =?UTF-8?q?recoil=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + src/app/RecoilWrapper.js | 6 ++++++ src/app/layout.js | 3 ++- src/app/roof2/page.jsx | 12 ++++++++++-- src/store/canvasAtom.js | 6 ++++++ yarn.lock | 21 ++++++++++++++++++++- 6 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 src/app/RecoilWrapper.js create mode 100644 src/store/canvasAtom.js diff --git a/package.json b/package.json index f2e0691a..468b23e1 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "next": "14.2.3", "react": "^18", "react-dom": "^18", + "recoil": "^0.7.7", "uuid": "^9.0.1" }, "devDependencies": { diff --git a/src/app/RecoilWrapper.js b/src/app/RecoilWrapper.js new file mode 100644 index 00000000..89cb9776 --- /dev/null +++ b/src/app/RecoilWrapper.js @@ -0,0 +1,6 @@ +'use client' +import { RecoilRoot } from 'recoil' + +export default function RecoilRootWrapper({ children }) { + return {children} +} diff --git a/src/app/layout.js b/src/app/layout.js index 663a8562..84095436 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,6 +1,7 @@ import { Inter } from 'next/font/google' import './globals.css' import Headers from '@/components/Headers' +import RecoilRootWrapper from './RecoilWrapper' const inter = Inter({ subsets: ['latin'] }) @@ -14,7 +15,7 @@ export default function RootLayout({ children }) { - {children} + {children} ) diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx index 03ab033c..81eaaec4 100644 --- a/src/app/roof2/page.jsx +++ b/src/app/roof2/page.jsx @@ -1,10 +1,18 @@ 'use client' import Hero from '@/components/Hero' -import Roof from '@/components/Roof' import Roof2 from '@/components/Roof2' +import { textState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { useRecoilState } from 'recoil' + +export default function Roof2Page() { + const [text, setText] = useRecoilState(textState) + + useEffect(() => { + console.log(text) + }, []) -export default function RoofPage() { return ( <> diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js new file mode 100644 index 00000000..e65aba28 --- /dev/null +++ b/src/store/canvasAtom.js @@ -0,0 +1,6 @@ +import { atom } from 'recoil' + +export const textState = atom({ + key: 'textState', + default: 'test text', +}) diff --git a/yarn.lock b/yarn.lock index f37579d4..d18ffe7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -646,6 +646,11 @@ graceful-fs@^4.2.11: resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +hamt_plus@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hamt_plus/-/hamt_plus-1.0.2.tgz#e21c252968c7e33b20f6a1b094cd85787a265601" + integrity sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA== + has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" @@ -1174,6 +1179,13 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" +recoil@^0.7.7: + version "0.7.7" + resolved "https://registry.yarnpkg.com/recoil/-/recoil-0.7.7.tgz#c5f2c843224384c9c09e4a62c060fb4c1454dc8e" + integrity sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ== + dependencies: + hamt_plus "1.0.2" + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" @@ -1331,7 +1343,14 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== From 9ff6152a9f3edcde18d8fc52e8b5f2e99a429b95 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 2 Jul 2024 16:38:11 +0900 Subject: [PATCH 041/113] =?UTF-8?q?=EB=8B=A4=EA=B0=81=ED=98=95=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20,=20font=20global?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 20 +++++++++++++------- src/components/fabric/QPolygon.js | 14 +++++--------- src/store/canvasAtom.js | 5 +++++ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index eb3cd57e..2e80fc2c 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -5,6 +5,8 @@ import QRect from '@/components/fabric/QRect' import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' import RangeSlider from './ui/RangeSlider' +import { useRecoilState } from 'recoil' +import { fontSizeState } from '@/store/canvasAtom' export default function Roof2() { const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots } = @@ -15,7 +17,7 @@ export default function Roof2() { //canvas 세로 사이즈 const [horizontalSize, setHorizontalSize] = useState(1000) // 글자크기 - const [fontSize, setFontSize] = useState(0) + const [fontSize, setFontSize] = useRecoilState(fontSizeState) const { mode, @@ -82,10 +84,10 @@ export default function Roof2() { } const canvasSizeMode = () => { - if(canvas) { - canvas.setWidth(parseInt(verticalSize)); - canvas.setHeight(parseInt(horizontalSize)); - canvas.renderAll(); + if (canvas) { + canvas.setWidth(parseInt(verticalSize)) + canvas.setHeight(parseInt(horizontalSize)) + canvas.renderAll() } } @@ -93,6 +95,10 @@ export default function Roof2() { canvasSizeMode() }, [verticalSize, horizontalSize]) + useEffect(() => { + console.log(`fontSize 바꼈다 ${fontSize}`) + }, [fontSize]) + return ( <> {canvas && ( @@ -233,7 +239,7 @@ export default function Roof2() {
@@ -242,7 +248,7 @@ export default function Roof2() { )}
- +
) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index b3e56063..5edf64d4 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -60,22 +60,18 @@ export default class QPolygon extends fabric.Polygon { const scaleX = this.scaleX const scaleY = this.scaleY - const points = this.getCurrentPoints() + const points = this.points for (let i = 0; i < points.length; i++) { - const start = this.getCurrentPoints()[i] - const currentStart = this.getCurrentPoints()[i] - const end = - this.getCurrentPoints()[(i + 1) % this.getCurrentPoints().length] - const currentEnd = - this.getCurrentPoints()[(i + 1) % this.getCurrentPoints().length] + const start = points[i] + const end = points[(i + 1) % points.length] const dx = end.x - start.x const dy = end.y - start.y const length = Math.sqrt(dx * dx + dy * dy) const midPoint = new fabric.Point( - (currentStart.x + currentEnd.x) / 2, - (currentStart.y + currentEnd.y) / 2, + (start.x + end.x) / 2, + (start.y + end.y) / 2, ) const text = new fabric.Text(length.toFixed(0), { diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index e65aba28..4cefe24b 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -4,3 +4,8 @@ export const textState = atom({ key: 'textState', default: 'test text', }) + +export const fontSizeState = atom({ + key: 'fontSizeState', + default: 10, +}) From 478f626970fe41c1dfa63cb4fe49fe4fcfe573d3 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 3 Jul 2024 10:10:39 +0900 Subject: [PATCH 042/113] =?UTF-8?q?=EB=A6=AC=EC=BD=94=EC=9D=BC=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9=20=EB=B0=8F=20=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=20=EA=B8=B0=EB=B3=B8=20=EA=B0=92=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 36 ++++++++++++++++++++++++++---------- src/hooks/useCanvas.js | 13 ++++++------- src/store/canvasAtom.js | 8 ++++++++ 3 files changed, 40 insertions(+), 17 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 2e80fc2c..2ba3776a 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -6,16 +6,19 @@ import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' import RangeSlider from './ui/RangeSlider' import { useRecoilState } from 'recoil' -import { fontSizeState } from '@/store/canvasAtom' +import { fontSizeState, canvasSizeState } from '@/store/canvasAtom' export default function Roof2() { const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots } = useCanvas('canvas') + //canvas 기본 사이즈 + const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState) + //canvas 가로 사이즈 - const [verticalSize, setVerticalSize] = useState(1000) + const [verticalSize, setVerticalSize] = useState(canvasSize.vertical) //canvas 세로 사이즈 - const [horizontalSize, setHorizontalSize] = useState(1000) + const [horizontalSize, setHorizontalSize] = useState(canvasSize.horizontal) // 글자크기 const [fontSize, setFontSize] = useRecoilState(fontSizeState) @@ -83,14 +86,25 @@ export default function Roof2() { } } + /** + * canvas 사이즈 변경 함수 + */ const canvasSizeMode = () => { if (canvas) { - canvas.setWidth(parseInt(verticalSize)) - canvas.setHeight(parseInt(horizontalSize)) + canvas.setWidth(horizontalSize) + canvas.setHeight(verticalSize) canvas.renderAll() + + setCanvasSize(() => ({ + vertical: verticalSize, + horizontal: horizontalSize + })) } } - + + /** + * 값 변경시 + */ useEffect(() => { canvasSizeMode() }, [verticalSize, horizontalSize]) @@ -222,19 +236,21 @@ export default function Roof2() {
diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 2ff40959..c7e89e7f 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -6,16 +6,15 @@ import { polygonPositionHandler, } from '@/app/util/canvas-util' -const CANVAS = { - WIDTH: 1000, - HEIGHT: 1000, -} +import { useRecoilState } from 'recoil' +import { canvasSizeState } from '@/store/canvasAtom' + export function useCanvas(id) { const [canvas, setCanvas] = useState() const [isLocked, setIsLocked] = useState(false) const [history, setHistory] = useState([]) - + const [canvasSize] = useRecoilState(canvasSizeState) const points = useRef([]) /** @@ -23,8 +22,8 @@ export function useCanvas(id) { */ useEffect(() => { const c = new fabric.Canvas(id, { - height: CANVAS.HEIGHT, - width: CANVAS.WIDTH, + height: canvasSize.vertical, + width: canvasSize.horizontal, backgroundColor: 'white', selection: false, }) diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 4cefe24b..e8d147e0 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -9,3 +9,11 @@ export const fontSizeState = atom({ key: 'fontSizeState', default: 10, }) + +export const canvasSizeState = atom({ + key: 'canvasSize', + default: { + vertical: 500, + horizontal : 500 + } +}) \ No newline at end of file From f0e7fb072cbf6dcccf9d2fedb2264a69df16947a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 3 Jul 2024 10:13:45 +0900 Subject: [PATCH 043/113] fontsize recoil --- src/components/Roof2.jsx | 16 +++++++++++++++- src/components/fabric/QLine.js | 5 +++-- src/components/fabric/QPolygon.js | 4 +++- src/components/fabric/QRect.js | 4 +++- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 2ba3776a..12b05a29 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -48,6 +48,7 @@ export default function Roof2() { stroke: 'black', width: 400, height: 100, + fontSize: fontSize, }) canvas?.add(rect) @@ -59,6 +60,7 @@ export default function Roof2() { const line = new QLine([50, 50, 200, 50], { stroke: 'black', strokeWidth: 2, + fontSize: fontSize, }) canvas?.add(line) @@ -79,6 +81,7 @@ export default function Roof2() { stroke: 'black', strokeWidth: 2, selectable: true, + fontSize: fontSize, }, ) @@ -110,7 +113,18 @@ export default function Roof2() { }, [verticalSize, horizontalSize]) useEffect(() => { - console.log(`fontSize 바꼈다 ${fontSize}`) + canvas + ?.getObjects() + .filter( + (obj) => + obj.type === 'textbox' || + obj.type === 'text' || + obj.type === 'i-text', + ) + .forEach((obj) => { + obj.set({ fontSize: fontSize }) + }) + canvas?.renderAll() }, [fontSize]) return ( diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 514d5dad..8637bd31 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -4,9 +4,10 @@ export default class QLine extends fabric.Line { #length #text #viewLengthText - + #fontSize constructor(points, option) { super(points, option) + this.#fontSize = option.fontSize ?? 16 this.#init(option) this.#addControl() } @@ -65,7 +66,7 @@ export default class QLine extends fabric.Line { const text = new fabric.Text(this.#length, { left: (this.x1 + this.x2) / 2, top: (this.y1 + this.y2) / 2, - fontSize: 16, + fontSize: this.#fontSize, selectable: false, }) this.#text = text diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 5edf64d4..5741b8bd 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -3,9 +3,11 @@ import { distanceBetweenPoints } from '@/app/util/canvas-util' export default class QPolygon extends fabric.Polygon { #viewLengthText #text = [] + #fontSize constructor(points, option) { super(points, option) + this.#fontSize = option.fontSize ?? 16 this.#init(points) this.#addControl() } @@ -77,7 +79,7 @@ export default class QPolygon extends fabric.Polygon { const text = new fabric.Text(length.toFixed(0), { left: midPoint.x, top: midPoint.y, - fontSize: 16, + fontSize: this.#fontSize, selectable: false, }) this.#text.push(text) diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js index db824a5b..eb15d6bf 100644 --- a/src/components/fabric/QRect.js +++ b/src/components/fabric/QRect.js @@ -2,8 +2,10 @@ import { fabric } from 'fabric' export default class QRect extends fabric.Rect { #text = [] #viewLengthText + #fontSize constructor(points, option) { super(points, option) + this.#fontSize = points.fontSize ?? 16 this.#init(points) this.#addControl() } @@ -77,7 +79,7 @@ export default class QRect extends fabric.Rect { const text = new fabric.Text(length.toFixed(0), { left: (line.start.x + line.end.x) / 2, top: (line.start.y + line.end.y) / 2, - fontSize: 16, + fontSize: this.#fontSize, selectable: false, }) this.#text.push(text) From 17645a4086eb1f4e26ebef927c0cf2ea142645f3 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 3 Jul 2024 10:29:33 +0900 Subject: [PATCH 044/113] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20=EC=9D=B4?= =?UTF-8?q?=EB=B2=A4=ED=8A=B8=20=EC=9E=AC=EB=93=B1=EB=A1=9D,=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20CANVAS=20=EA=B0=9D=EC=B2=B4=20=EC=B0=B8=EC=A1=B0?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EA=B0=92=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useCanvas.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index c7e89e7f..c38acd4e 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -9,7 +9,6 @@ import { import { useRecoilState } from 'recoil' import { canvasSizeState } from '@/store/canvasAtom' - export function useCanvas(id) { const [canvas, setCanvas] = useState() const [isLocked, setIsLocked] = useState(false) @@ -41,6 +40,12 @@ export function useCanvas(id) { } }, []) + useEffect(() => { + // canvas 사이즈가 변경되면 다시 + removeEventOnCanvas() + addEventOnCanvas() + }, [canvasSize]) + /** * 캔버스 초기화 */ @@ -137,7 +142,7 @@ export function useCanvas(id) { // 가로선을 그립니다. const horizontalLine = new fabric.Line( - [0, pointer.y, CANVAS.WIDTH, pointer.y], + [0, pointer.y, canvasSize.horizontal, pointer.y], { stroke: 'black', strokeWidth: 1, @@ -149,7 +154,7 @@ export function useCanvas(id) { // 세로선을 그립니다. const verticalLine = new fabric.Line( - [pointer.x, 0, pointer.x, CANVAS.HEIGHT], + [pointer.x, 0, pointer.x, canvasSize.vertical], { stroke: 'black', strokeWidth: 1, From 3d7d2ab0dcc6a5c7014dfdfe6a69a22dcd5697ad Mon Sep 17 00:00:00 2001 From: nalpari Date: Wed, 3 Jul 2024 10:34:25 +0900 Subject: [PATCH 045/113] =?UTF-8?q?refactor:=20util=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20=EC=9C=84=EC=B9=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit nextjs 폴더명 예약 문제로 util 폴더 경로 수정 --- src/components/Roof.jsx | 2 +- src/components/fabric/QPolygon.js | 2 +- src/hooks/useCanvas.js | 2 +- src/hooks/useMode.js | 2 +- src/{app => }/util/canvas-util.js | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename src/{app => }/util/canvas-util.js (100%) diff --git a/src/components/Roof.jsx b/src/components/Roof.jsx index d135c1f6..9fd3aed2 100644 --- a/src/components/Roof.jsx +++ b/src/components/Roof.jsx @@ -1,4 +1,4 @@ -import { addDistanceTextToPolygon, getDistance } from '@/app/util/canvas-util' +import { addDistanceTextToPolygon, getDistance } from '@/util/canvas-util' import { useCanvas } from '@/hooks/useCanvas' import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 5741b8bd..6af80604 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,5 +1,5 @@ import { fabric } from 'fabric' -import { distanceBetweenPoints } from '@/app/util/canvas-util' +import { distanceBetweenPoints } from '@/util/canvas-util' export default class QPolygon extends fabric.Polygon { #viewLengthText #text = [] diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index c38acd4e..177c9694 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -4,7 +4,7 @@ import { actionHandler, anchorWrapper, polygonPositionHandler, -} from '@/app/util/canvas-util' +} from '@/util/canvas-util' import { useRecoilState } from 'recoil' import { canvasSizeState } from '@/store/canvasAtom' diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 89cc8b56..4960f7e7 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -2,7 +2,7 @@ import { useRef, useState } from 'react' import QLine from '@/components/fabric/QLine' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' -import { getStartIndex, rearrangeArray } from '@/app/util/canvas-util' +import { getStartIndex, rearrangeArray } from '@/util/canvas-util' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 diff --git a/src/app/util/canvas-util.js b/src/util/canvas-util.js similarity index 100% rename from src/app/util/canvas-util.js rename to src/util/canvas-util.js From 2e3a933dbb09a4569d4f0b6bda3516836cdf09ee Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 3 Jul 2024 12:02:30 +0900 Subject: [PATCH 046/113] =?UTF-8?q?Q=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=EC=8B=9C=20=ED=8F=B0=ED=8A=B8=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=EB=8A=94=20=ED=95=84=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 4 ++-- src/components/fabric/QLine.js | 6 +++++- src/components/fabric/QPolygon.js | 14 +++++++++++++- src/components/fabric/QRect.js | 18 +++++++++++------- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 12b05a29..5479df91 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -100,11 +100,11 @@ export default function Roof2() { setCanvasSize(() => ({ vertical: verticalSize, - horizontal: horizontalSize + horizontal: horizontalSize, })) } } - + /** * 값 변경시 */ diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 8637bd31..f2fa9ce4 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -5,9 +5,13 @@ export default class QLine extends fabric.Line { #text #viewLengthText #fontSize + type = 'QLine' constructor(points, option) { + if (option.fontSize) { + throw new Error('Font size is required.') + } super(points, option) - this.#fontSize = option.fontSize ?? 16 + this.#fontSize = option.fontSize this.#init(option) this.#addControl() } diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 6af80604..9c57a43c 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -4,10 +4,14 @@ export default class QPolygon extends fabric.Polygon { #viewLengthText #text = [] #fontSize + type = 'QPolygon' constructor(points, option) { + if (option.fontSize) { + throw new Error('Font size is required.') + } super(points, option) - this.#fontSize = option.fontSize ?? 16 + this.#fontSize = option.fontSize this.#init(points) this.#addControl() } @@ -48,6 +52,14 @@ export default class QPolygon extends fabric.Polygon { }) } + setTexts(texts) { + this.#text = texts + } + + getTexts() { + return this.#text + } + #addLengthText() { if (this.#text.length > 0) { this.#text.forEach((text) => { diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js index eb15d6bf..8edb9884 100644 --- a/src/components/fabric/QRect.js +++ b/src/components/fabric/QRect.js @@ -3,15 +3,19 @@ export default class QRect extends fabric.Rect { #text = [] #viewLengthText #fontSize - constructor(points, option) { - super(points, option) - this.#fontSize = points.fontSize ?? 16 - this.#init(points) + type = 'QRect' + constructor(option) { + if (option.fontSize) { + throw new Error('Font size is required.') + } + super(option) + this.#fontSize = option.fontSize + this.#init(option) this.#addControl() } - #init(points) { - this.#viewLengthText = points.viewLengthText ?? true + #init(option) { + this.#viewLengthText = option.viewLengthText ?? true } setViewLengthText(bool) { @@ -79,7 +83,7 @@ export default class QRect extends fabric.Rect { const text = new fabric.Text(length.toFixed(0), { left: (line.start.x + line.end.x) / 2, top: (line.start.y + line.end.y) / 2, - fontSize: this.#fontSize, + fontSize: this.fontSize, selectable: false, }) this.#text.push(text) From 8b97fe0b31fa6f0f6d19a3f69f121b9a7b4dfc53 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 3 Jul 2024 12:03:44 +0900 Subject: [PATCH 047/113] =?UTF-8?q?Q=EC=BB=B4=ED=8F=AC=EB=84=8C=ED=8A=B8?= =?UTF-8?q?=20=EC=83=9D=EC=84=B1=EC=8B=9C=20=ED=8F=B0=ED=8A=B8=EC=82=AC?= =?UTF-8?q?=EC=9D=B4=EC=A6=88=EB=8A=94=20=ED=95=84=EC=88=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 2 +- src/components/fabric/QPolygon.js | 2 +- src/components/fabric/QRect.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index f2fa9ce4..545ff76e 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -7,7 +7,7 @@ export default class QLine extends fabric.Line { #fontSize type = 'QLine' constructor(points, option) { - if (option.fontSize) { + if (!option.fontSize) { throw new Error('Font size is required.') } super(points, option) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 9c57a43c..035c3d99 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -7,7 +7,7 @@ export default class QPolygon extends fabric.Polygon { type = 'QPolygon' constructor(points, option) { - if (option.fontSize) { + if (!option.fontSize) { throw new Error('Font size is required.') } super(points, option) diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js index 8edb9884..ff9e7850 100644 --- a/src/components/fabric/QRect.js +++ b/src/components/fabric/QRect.js @@ -5,7 +5,7 @@ export default class QRect extends fabric.Rect { #fontSize type = 'QRect' constructor(option) { - if (option.fontSize) { + if (!option.fontSize) { throw new Error('Font size is required.') } super(option) From 63a965d118fa18436442eceee996f8727ff395c5 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 3 Jul 2024 12:32:48 +0900 Subject: [PATCH 048/113] =?UTF-8?q?font=20=EB=B3=80=EA=B2=BD=EC=8B=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 15 --------------- src/components/fabric/QLine.js | 5 +++++ src/components/fabric/QPolygon.js | 5 +++++ src/components/fabric/QRect.js | 7 ++++++- src/hooks/useCanvas.js | 30 +++++++++++++++++++++++++++++- src/hooks/useMode.js | 8 ++++++++ 6 files changed, 53 insertions(+), 17 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 5479df91..2981e5ca 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -112,21 +112,6 @@ export default function Roof2() { canvasSizeMode() }, [verticalSize, horizontalSize]) - useEffect(() => { - canvas - ?.getObjects() - .filter( - (obj) => - obj.type === 'textbox' || - obj.type === 'text' || - obj.type === 'i-text', - ) - .forEach((obj) => { - obj.set({ fontSize: fontSize }) - }) - canvas?.renderAll() - }, [fontSize]) - return ( <> {canvas && ( diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 545ff76e..4bce6a55 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -61,6 +61,11 @@ export default class QLine extends fabric.Line { this.#addLengthText() } + setFontSize(fontSize) { + this.#fontSize = fontSize + this.#addLengthText() + } + #addLengthText() { if (this.#text) { this.canvas.remove(this.#text) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 035c3d99..6a4e964e 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -99,6 +99,11 @@ export default class QPolygon extends fabric.Polygon { } } + setFontSize(fontSize) { + this.#fontSize = fontSize + this.#addLengthText() + } + getCurrentPoints() { const scaleX = this.scaleX const scaleY = this.scaleY diff --git a/src/components/fabric/QRect.js b/src/components/fabric/QRect.js index ff9e7850..ad6c8ae9 100644 --- a/src/components/fabric/QRect.js +++ b/src/components/fabric/QRect.js @@ -23,6 +23,11 @@ export default class QRect extends fabric.Rect { this.#addLengthText() } + setFontSize(fontSize) { + this.#fontSize = fontSize + this.#addLengthText() + } + #addControl() { this.on('removed', () => { if (this.#text.length > 0) { @@ -83,7 +88,7 @@ export default class QRect extends fabric.Rect { const text = new fabric.Text(length.toFixed(0), { left: (line.start.x + line.end.x) / 2, top: (line.start.y + line.end.y) / 2, - fontSize: this.fontSize, + fontSize: this.#fontSize, selectable: false, }) this.#text.push(text) diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 177c9694..0bf0c872 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -7,13 +7,14 @@ import { } from '@/util/canvas-util' import { useRecoilState } from 'recoil' -import { canvasSizeState } from '@/store/canvasAtom' +import { canvasSizeState, fontSizeState } from '@/store/canvasAtom' export function useCanvas(id) { const [canvas, setCanvas] = useState() const [isLocked, setIsLocked] = useState(false) const [history, setHistory] = useState([]) const [canvasSize] = useRecoilState(canvasSizeState) + const [fontSize] = useRecoilState(fontSizeState) const points = useRef([]) /** @@ -46,6 +47,33 @@ export function useCanvas(id) { addEventOnCanvas() }, [canvasSize]) + useEffect(() => { + canvas + ?.getObjects() + .filter( + (obj) => + obj.type === 'textbox' || + obj.type === 'text' || + obj.type === 'i-text', + ) + .forEach((obj) => { + obj.set({ fontSize: fontSize }) + }) + + canvas + ?.getObjects() + .filter( + (obj) => + obj.type === 'Qline' || + obj.type === 'QPolygon' || + obj.type === 'QRect', + ) + .forEach((obj) => { + obj.setFontSize(fontSize) + }) + canvas?.renderAll() + }, [fontSize]) + /** * 캔버스 초기화 */ diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 4960f7e7..952b678b 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -3,6 +3,8 @@ import QLine from '@/components/fabric/QLine' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' import { getStartIndex, rearrangeArray } from '@/util/canvas-util' +import { useRecoilState } from 'recoil' +import { fontSizeState } from '@/store/canvasAtom' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 @@ -20,6 +22,7 @@ export function useMode() { const historyLines = useRef([]) const [canvas, setCanvas] = useState(null) const [zoom, setZoom] = useState(100) + const [fontSize] = useRecoilState(fontSizeState) const addEvent = (mode) => { switch (mode) { @@ -153,6 +156,7 @@ export function useMode() { selectable: false, viewLengthText: true, direction: getDirection(points.current[0], points.current[1]), + fontSize: fontSize, }, ) @@ -237,6 +241,7 @@ export function useMode() { strokeWidth: 2, viewLengthText: true, selectable: false, + fontSize: fontSize, }, ) @@ -295,6 +300,7 @@ export function useMode() { fill: 'transparent', stroke: 'black', transparentCorners: false, + fontSize: fontSize, }) canvas.remove(rect) canvas.add(qRect) @@ -335,6 +341,7 @@ export function useMode() { selectable: false, viewLengthText: true, direction: getDirection(a, b), + fontSize: fontSize, }) historyLines.current.push(line) @@ -365,6 +372,7 @@ export function useMode() { fill: 'transparent', viewLengthText: true, selectable: true, + fontSize: fontSize, }) // 새로운 다각형 객체를 캔버스에 추가합니다. From 84e95a29dfd4ed87a7cfa78691b70d42194e6b05 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 3 Jul 2024 14:24:26 +0900 Subject: [PATCH 049/113] =?UTF-8?q?fontsize=20=EA=B0=92=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 952b678b..e9cf30d5 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -80,7 +80,7 @@ export function useMode() { distanceText = new fabric.Text(`${minDistance.toFixed(2)}`, { left: pointer.x, top: pointer.y, - fontSize: 16, + fontSize: fontSize, }) canvas?.add(distanceText) } @@ -217,7 +217,7 @@ export function useMode() { left: pointer.x, top: pointer.y, width: 150, // 텍스트박스의 너비를 설정합니다. - fontSize: 16, // 텍스트의 크기를 설정합니다. + fontSize: fontSize, // 텍스트의 크기를 설정합니다. }) canvas?.add(textbox) From 5814c48b9ae7d73934c9c3416fffd60dd7dbbc26 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 4 Jul 2024 13:00:09 +0900 Subject: [PATCH 050/113] =?UTF-8?q?=EA=B8=B0=EB=B3=B8=20=EC=BA=94=EB=B2=84?= =?UTF-8?q?=EC=8A=A4=20=EC=82=AC=EC=9D=B4=EC=A6=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 4 ++-- src/components/fabric/QPolygon.js | 5 +++++ src/hooks/useCanvas.js | 2 +- src/store/canvasAtom.js | 8 ++++---- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 2981e5ca..4acc9712 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -234,7 +234,7 @@ export default function Roof2() {
0) { this.#text.forEach((text) => { this.canvas.remove(text) @@ -235,4 +236,8 @@ export default class QPolygon extends fabric.Polygon { return intersects % 2 === 1 } + + getCurrentOptions = () => { + return this.options + } } diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 0bf0c872..9d860234 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -64,7 +64,7 @@ export function useCanvas(id) { ?.getObjects() .filter( (obj) => - obj.type === 'Qline' || + obj.type === 'QLine' || obj.type === 'QPolygon' || obj.type === 'QRect', ) diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index e8d147e0..4cdaaa32 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -13,7 +13,7 @@ export const fontSizeState = atom({ export const canvasSizeState = atom({ key: 'canvasSize', default: { - vertical: 500, - horizontal : 500 - } -}) \ No newline at end of file + vertical: 1000, + horizontal: 1000, + }, +}) From 9ae441fff6eee8ebdd51437e62e53b4cd0420eff Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 4 Jul 2024 14:15:39 +0900 Subject: [PATCH 051/113] readme --- README.md | 41 ++++++++++------------------------------- 1 file changed, 10 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index 0dc9ea2b..69ed67c8 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,15 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +# 점 갯수 별 타입 -## Getting Started +## 점 6개 -First, run the development server: +### type1 + -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev -``` +### type2 + -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +### type3 + -You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. - -This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. - -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +### type4 + \ No newline at end of file From 7649655b174b8a481afc15088034343d42388ebf Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 4 Jul 2024 14:19:50 +0900 Subject: [PATCH 052/113] =?UTF-8?q?line=20=EC=A0=84=EB=B6=80=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index e9cf30d5..1fac311d 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -361,9 +361,7 @@ export function useMode() { // 모든 라인 객체를 캔버스에서 제거합니다. lines.forEach((line) => { - if (line.type === 'line') { - canvas?.remove(line) - } + canvas?.remove(line) }) // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다. From e7814a784bae357bf9db8f1293992f080c168e2c Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 4 Jul 2024 16:09:21 +0900 Subject: [PATCH 053/113] =?UTF-8?q?length=20=EC=86=8D=EC=84=B1=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 4bce6a55..66735f69 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -1,7 +1,7 @@ import { fabric } from 'fabric' export default class QLine extends fabric.Line { - #length + length #text #viewLengthText #fontSize @@ -20,7 +20,7 @@ export default class QLine extends fabric.Line { // 선의 길이를 계산하여 length 속성을 초기화합니다. const dx = this.x2 - this.x1 const dy = this.y2 - this.y1 - this.#length = Math.sqrt(dx * dx + dy * dy).toFixed(0) + this.length = Math.sqrt(dx * dx + dy * dy).toFixed(0) this.#viewLengthText = option.viewLengthText ?? true } @@ -46,7 +46,7 @@ export default class QLine extends fabric.Line { const dx = this.x2 - this.x1 const dy = this.y2 - this.y1 const length = Math.sqrt(dx * dx + dy * dy) - this.#length = length.toFixed(0) // 선의 길이를 length 속성에 저장합니다. + this.length = length.toFixed(0) // 선의 길이를 length 속성에 저장합니다. this.#addLengthText() }) @@ -72,7 +72,7 @@ export default class QLine extends fabric.Line { } if (this.#viewLengthText) { - const text = new fabric.Text(this.#length, { + const text = new fabric.Text(this.length, { left: (this.x1 + this.x2) / 2, top: (this.y1 + this.y2) / 2, fontSize: this.#fontSize, From 0ba9b9a4e2c1536eb24579e825989f05870a1177 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 4 Jul 2024 16:11:23 +0900 Subject: [PATCH 054/113] =?UTF-8?q?length=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 66735f69..a5d63c83 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -20,7 +20,7 @@ export default class QLine extends fabric.Line { // 선의 길이를 계산하여 length 속성을 초기화합니다. const dx = this.x2 - this.x1 const dy = this.y2 - this.y1 - this.length = Math.sqrt(dx * dx + dy * dy).toFixed(0) + this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) this.#viewLengthText = option.viewLengthText ?? true } @@ -46,7 +46,7 @@ export default class QLine extends fabric.Line { const dx = this.x2 - this.x1 const dy = this.y2 - this.y1 const length = Math.sqrt(dx * dx + dy * dy) - this.length = length.toFixed(0) // 선의 길이를 length 속성에 저장합니다. + this.length = Number(length.toFixed(0)) // 선의 길이를 length 속성에 저장합니다. this.#addLengthText() }) @@ -72,7 +72,7 @@ export default class QLine extends fabric.Line { } if (this.#viewLengthText) { - const text = new fabric.Text(this.length, { + const text = new fabric.Text(this.length.toString(), { left: (this.x1 + this.x2) / 2, top: (this.y1 + this.y2) / 2, fontSize: this.#fontSize, From 1cc33450ef107f0f8895b4082ce213f7e0e2004b Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 4 Jul 2024 16:51:22 +0900 Subject: [PATCH 055/113] QPolygon2 --- README.md | 2 +- src/components/Roof2.jsx | 105 ++++++++++++++++++++++++++++- src/components/fabric/QPolygon.js | 12 ++-- src/components/fabric/QPolygon2.js | 79 ++++++++++++++++++++++ 4 files changed, 187 insertions(+), 11 deletions(-) create mode 100644 src/components/fabric/QPolygon2.js diff --git a/README.md b/README.md index 69ed67c8..916119e2 100644 --- a/README.md +++ b/README.md @@ -12,4 +12,4 @@ ### type4 - \ No newline at end of file + \ No newline at end of file diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 4acc9712..496d6639 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -4,13 +4,19 @@ import { Mode, useMode } from '@/hooks/useMode' import QRect from '@/components/fabric/QRect' import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' +import QPolygon2 from '@/components/fabric/QPolygon2' import RangeSlider from './ui/RangeSlider' import { useRecoilState } from 'recoil' import { fontSizeState, canvasSizeState } from '@/store/canvasAtom' export default function Roof2() { - const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots } = - useCanvas('canvas') + const { + canvas, + handleRedo, + handleUndo, + setCanvasBackgroundWithDots, + saveImage, + } = useCanvas('canvas') //canvas 기본 사이즈 const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState) @@ -86,6 +92,9 @@ export default function Roof2() { ) canvas?.add(polygon) + console.log(polygon) + + // polygon.fillCell({ width: 50, height: 30, padding: 10 }) } } @@ -112,6 +121,70 @@ export default function Roof2() { canvasSizeMode() }, [verticalSize, horizontalSize]) + const addPolygonType1 = () => { + if (canvas) { + const polygon = new QPolygon( + [ + { x: 100, y: 100 }, + { x: 800, y: 100 }, + { x: 800, y: 800 }, + { x: 500, y: 800 }, + { x: 500, y: 400 }, + { x: 100, y: 400 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + }, + ) + + canvas?.add(polygon) + + polygon.fillCell({ width: 20, height: 20, padding: 10 }) + } + } + + const rotate = () => { + const rect = canvas?.getObjects().find((obj) => obj.type === 'QRect') + if (!rect) { + alert('사각형을 먼저 만들어주세요.') + return + } + const angle = prompt('각도를 입력해주세요.', '0') + if (rect) { + rect.angle = parseInt(angle) + canvas?.renderAll() + } + } + + const makeQPolygon2 = () => { + if (canvas) { + const polygon2 = new QPolygon2( + [ + { x: 100, y: 100 }, + { x: 800, y: 100 }, + { x: 800, y: 800 }, + { x: 500, y: 800 }, + { x: 500, y: 400 }, + { x: 100, y: 400 }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + }, + canvas, + ) + + canvas?.add(polygon2) + } + } + return ( <> {canvas && ( @@ -230,6 +303,34 @@ export default function Roof2() { > 점선 추가 + + + +
diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 6da1694f..ab7a7171 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -40,6 +40,7 @@ export default class QPolygon extends fabric.Polygon { }) this.on('modified', (e) => { + console.log(this) this.#addLengthText() }) @@ -61,7 +62,6 @@ export default class QPolygon extends fabric.Polygon { } #addLengthText() { - return false if (this.#text.length > 0) { this.#text.forEach((text) => { this.canvas.remove(text) @@ -75,13 +75,13 @@ export default class QPolygon extends fabric.Polygon { const scaleX = this.scaleX const scaleY = this.scaleY - const points = this.points + const points = this.getCurrentPoints() for (let i = 0; i < points.length; i++) { const start = points[i] const end = points[(i + 1) % points.length] - const dx = end.x - start.x - const dy = end.y - start.y + const dx = (end.x - start.x) * scaleX + const dy = (end.y - start.y) * scaleY const length = Math.sqrt(dx * dx + dy * dy) const midPoint = new fabric.Point( @@ -236,8 +236,4 @@ export default class QPolygon extends fabric.Polygon { return intersects % 2 === 1 } - - getCurrentOptions = () => { - return this.options - } } diff --git a/src/components/fabric/QPolygon2.js b/src/components/fabric/QPolygon2.js new file mode 100644 index 00000000..b59356c6 --- /dev/null +++ b/src/components/fabric/QPolygon2.js @@ -0,0 +1,79 @@ +import { fabric } from 'fabric' + +export default class QPolygon2 extends fabric.Group { + type = 'QPolygon2' + polygon + points + texts = [] + canvas + constructor(points, options, canvas) { + const polygon = new fabric.Polygon(points, options) + super([polygon], {}) + this.points = points + this.polygon = polygon + this.canvas = canvas + + this.#init() + this.#addEvent() + } + + #init() { + this.#addLengthText() + } + + #addEvent() { + this.on('modified', () => { + // this.#addLengthText() + }) + } + + #addLengthText() { + const points = this.getCurrentPoints() + + points.forEach((start, i) => { + const end = points[(i + 1) % points.length] + const dx = end.x - start.x + const dy = end.y - start.y + const length = Math.sqrt(dx * dx + dy * dy) + + const midPoint = new fabric.Point( + (start.x + end.x) / 2, + (start.y + end.y) / 2, + ) + + if (this.texts[i]) { + // Update existing text + this.texts[i].set({ + text: length.toFixed(0), + left: midPoint.x, + top: midPoint.y, + }) + } else { + // Create new text object if it doesn't exist + const text = new fabric.Text(length.toFixed(0), { + left: midPoint.x, + top: midPoint.y, + fontSize: 16, + selectable: false, + }) + + this.texts.push(text) + this.addWithUpdate(text) + } + }) + + this.canvas.renderAll() + } + + getCurrentPoints() { + const scaleX = this.scaleX + const scaleY = this.scaleY + + return this.points.map((point) => { + return { + x: point.x * scaleX, + y: point.y * scaleY, + } + }) + } +} From 88a41236f40784848f32d693b65ffe5cb0dd0b7f Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 4 Jul 2024 16:51:54 +0900 Subject: [PATCH 056/113] =?UTF-8?q?=E3=84=B1=EC=9E=90=20=EB=AA=A8=EC=96=91?= =?UTF-8?q?=20shape=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 1fac311d..2fa960ec 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -353,6 +353,47 @@ export function useMode() { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current if (!otherLines) { + + const sortedIndex = getStartIndex(lines) + const tmpArraySorted = rearrangeArray(lines, sortedIndex) + + function findTopTwoIndexesByDistance(objArr) { + if (objArr.length < 2) { + return []; // 배열의 길이가 2보다 작으면 빈 배열 반환 + } + + let firstIndex = -1; + let secondIndex = -1; + let firstDistance = -Infinity; + let secondDistance = -Infinity; + + for (let i = 0; i < objArr.length; i++) { + const distance = objArr[i].length; + + if (distance > firstDistance) { + secondDistance = firstDistance; + secondIndex = firstIndex; + firstDistance = distance; + firstIndex = i; + } else if (distance > secondDistance) { + secondDistance = distance; + secondIndex = i; + } + } + + return [firstIndex, secondIndex]; + } + + const topIndex = findTopTwoIndexesByDistance(tmpArraySorted); + + const shape = 0; + + if(topIndex[0] === 2) { + if(topIndex[1] === 3) shape = 1 + }else if(topIndex === 1){ + if(topIndex[1] === 2) shape = 4 + } + historyLines.current = [] } From 41b8dea43a8877c2c2342fbb7cfebd4592550c81 Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 04:14:25 +0900 Subject: [PATCH 057/113] fix: syntax bug fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit const 변수에 값 재할당 오류 --- src/hooks/useMode.js | 57 ++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 2fa960ec..32298b17 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -353,47 +353,46 @@ export function useMode() { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current if (!otherLines) { - const sortedIndex = getStartIndex(lines) const tmpArraySorted = rearrangeArray(lines, sortedIndex) - + function findTopTwoIndexesByDistance(objArr) { if (objArr.length < 2) { - return []; // 배열의 길이가 2보다 작으면 빈 배열 반환 + return [] // 배열의 길이가 2보다 작으면 빈 배열 반환 } - - let firstIndex = -1; - let secondIndex = -1; - let firstDistance = -Infinity; - let secondDistance = -Infinity; - + + let firstIndex = -1 + let secondIndex = -1 + let firstDistance = -Infinity + let secondDistance = -Infinity + for (let i = 0; i < objArr.length; i++) { - const distance = objArr[i].length; - - if (distance > firstDistance) { - secondDistance = firstDistance; - secondIndex = firstIndex; - firstDistance = distance; - firstIndex = i; - } else if (distance > secondDistance) { - secondDistance = distance; - secondIndex = i; - } + const distance = objArr[i].length + + if (distance > firstDistance) { + secondDistance = firstDistance + secondIndex = firstIndex + firstDistance = distance + firstIndex = i + } else if (distance > secondDistance) { + secondDistance = distance + secondIndex = i + } } - - return [firstIndex, secondIndex]; + + return [firstIndex, secondIndex] } - const topIndex = findTopTwoIndexesByDistance(tmpArraySorted); + const topIndex = findTopTwoIndexesByDistance(tmpArraySorted) - const shape = 0; + let shape = 0 - if(topIndex[0] === 2) { - if(topIndex[1] === 3) shape = 1 - }else if(topIndex === 1){ - if(topIndex[1] === 2) shape = 4 + if (topIndex[0] === 2) { + if (topIndex[1] === 3) shape = 1 + } else if (topIndex === 1) { + if (topIndex[1] === 2) shape = 4 } - + historyLines.current = [] } From a3cd1606db08ee832a82669c6e614822d5a09343 Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 04:20:06 +0900 Subject: [PATCH 058/113] fix: Refactor useMode hook to fix line positioning bug --- src/hooks/useMode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 32298b17..ebe02701 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -586,7 +586,7 @@ export function useMode() { }) } else { newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, + x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, From 9ef112e04d85a59bcbc9cb4ea47672e93e7858ab Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 09:16:12 +0900 Subject: [PATCH 059/113] fix: Refactor useMode hook to fix line positioning bug --- src/hooks/useMode.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index ebe02701..88d50d4a 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -457,10 +457,10 @@ export function useMode() { if (historyLines.current[i].direction === 'top') { if (prev.direction !== 'right') { newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 + 50, + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, }) } else { newOuterlines.push({ @@ -499,10 +499,10 @@ export function useMode() { }) } else { newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 - 50, + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, }) } } else { @@ -545,16 +545,16 @@ export function useMode() { if (prev?.direction !== 'top') { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 - 50, + y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 - 50, + y2: historyLines.current[i].y2 + 50, }) } else { newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 - 50, + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, }) } } From 4a16fcbf3d88dcd1943985739416a357409e5505 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 5 Jul 2024 09:27:12 +0900 Subject: [PATCH 060/113] =?UTF-8?q?QPolygon=20group=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 10 +- src/components/fabric/QPolygon.js | 221 ++++++++++++++--------------- src/components/fabric/QPolygon2.js | 79 ----------- src/hooks/useMode.js | 19 ++- 4 files changed, 128 insertions(+), 201 deletions(-) delete mode 100644 src/components/fabric/QPolygon2.js diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 496d6639..f17612a6 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -4,10 +4,10 @@ import { Mode, useMode } from '@/hooks/useMode' import QRect from '@/components/fabric/QRect' import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' -import QPolygon2 from '@/components/fabric/QPolygon2' + import RangeSlider from './ui/RangeSlider' import { useRecoilState } from 'recoil' -import { fontSizeState, canvasSizeState } from '@/store/canvasAtom' +import { canvasSizeState, fontSizeState } from '@/store/canvasAtom' export default function Roof2() { const { @@ -89,12 +89,13 @@ export default function Roof2() { selectable: true, fontSize: fontSize, }, + canvas, ) canvas?.add(polygon) console.log(polygon) - // polygon.fillCell({ width: 50, height: 30, padding: 10 }) + polygon.fillCell({ width: 50, height: 30, padding: 10 }) } } @@ -139,6 +140,7 @@ export default function Roof2() { selectable: true, fontSize: fontSize, }, + canvas, ) canvas?.add(polygon) @@ -162,7 +164,7 @@ export default function Roof2() { const makeQPolygon2 = () => { if (canvas) { - const polygon2 = new QPolygon2( + const polygon2 = new QPolygon( [ { x: 100, y: 100 }, { x: 800, y: 100 }, diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index ab7a7171..c7dcf53c 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,87 +1,63 @@ import { fabric } from 'fabric' import { distanceBetweenPoints } from '@/util/canvas-util' -export default class QPolygon extends fabric.Polygon { - #viewLengthText - #text = [] - #fontSize - type = 'QPolygon' - constructor(points, option) { - if (!option.fontSize) { +export default class QPolygon extends fabric.Group { + type = 'QPolygon' + polygon + points + texts = [] + canvas + fontSize + constructor(points, options, canvas) { + if (!options.fontSize) { throw new Error('Font size is required.') } - super(points, option) - this.#fontSize = option.fontSize - this.#init(points) - this.#addControl() + if (!canvas) { + throw new Error('Canvas is required.') + } + + const polygon = new fabric.Polygon(points, options) + super([polygon], {}) + this.fontSize = options.fontSize + this.points = points + this.polygon = polygon + this.canvas = canvas + + this.#init() + this.#addEvent() } - #init(points) { - this.#viewLengthText = points.viewLengthText ?? true - } - - setViewLengthText(bool) { - this.#viewLengthText = bool + #init() { this.#addLengthText() } - #addControl() { - this.on('removed', () => { - if (this.#text.length > 0) { - this.#text.forEach((text) => { - this.canvas.remove(text) - }) - this.#text = [] - } - }) - - this.on('added', () => { - this.#addLengthText() - }) - - this.on('modified', (e) => { - console.log(this) - this.#addLengthText() - }) - + #addEvent() { this.on('scaling', (e) => { - this.#addLengthText() - }) - - this.on('moving', () => { - this.#addLengthText() + this.#updateLengthText() }) } - setTexts(texts) { - this.#text = texts - } - - getTexts() { - return this.#text + setFontSize(fontSize) { + this.texts.forEach((text) => { + text.set({ fontSize }) + this.canvas.requestRenderAll() + }) + this.fontSize = fontSize } #addLengthText() { - if (this.#text.length > 0) { - this.#text.forEach((text) => { + if (this.texts.length > 0) { + this.texts.forEach((text) => { this.canvas.remove(text) }) - this.#text = [] + this.texts = [] } - if (!this.#viewLengthText) { - return - } - - const scaleX = this.scaleX - const scaleY = this.scaleY - const points = this.getCurrentPoints() - for (let i = 0; i < points.length; i++) { - const start = points[i] + points.forEach((start, i) => { const end = points[(i + 1) % points.length] - const dx = (end.x - start.x) * scaleX - const dy = (end.y - start.y) * scaleY + const dx = end.x - start.x + const dy = end.y - start.y const length = Math.sqrt(dx * dx + dy * dy) const midPoint = new fabric.Point( @@ -89,69 +65,39 @@ export default class QPolygon extends fabric.Polygon { (start.y + end.y) / 2, ) + // Create new text object if it doesn't exist const text = new fabric.Text(length.toFixed(0), { left: midPoint.x, top: midPoint.y, - fontSize: this.#fontSize, + fontSize: this.fontSize, selectable: false, }) - this.#text.push(text) - this.canvas.add(text) - } - } - setFontSize(fontSize) { - this.#fontSize = fontSize - this.#addLengthText() - } - - getCurrentPoints() { - const scaleX = this.scaleX - const scaleY = this.scaleY - - return this.points.map((point) => { - return { - x: point.x * scaleX + this.left, - y: point.y * scaleY + this.top, - } + this.texts.push(text) + this.addWithUpdate(text) }) + + this.canvas.renderAll() } - #distanceFromEdge(point) { - const vertices = this.points - let minDistance = Infinity + #updateLengthText() { + const points = this.getCurrentPoints() - for (let i = 0; i < vertices.length; i++) { - let vertex1 = vertices[i] - let vertex2 = vertices[(i + 1) % vertices.length] + points.forEach((start, i) => { + const end = points[(i + 1) % points.length] + const dx = end.x - start.x + const dy = end.y - start.y + const length = Math.sqrt(dx * dx + dy * dy) - const dx = vertex2.x - vertex1.x - const dy = vertex2.y - vertex1.y + // Update the text object with the new length + this.texts[i].set({ text: length.toFixed(0) }) + }) - const t = - ((point.x - vertex1.x) * dx + (point.y - vertex1.y) * dy) / - (dx * dx + dy * dy) - - let closestPoint - if (t < 0) { - closestPoint = vertex1 - } else if (t > 1) { - closestPoint = vertex2 - } else { - closestPoint = new fabric.Point(vertex1.x + t * dx, vertex1.y + t * dy) - } - - const distance = distanceBetweenPoints(point, closestPoint) - if (distance < minDistance) { - minDistance = distance - } - } - - return minDistance + this.canvas.renderAll() } fillCell(cell = { width: 50, height: 100, padding: 10 }) { - const points = this.points + const points = this.getCurrentPoints() let bounds try { @@ -195,7 +141,7 @@ export default class QPolygon extends fabric.Polygon { ) if (isInside) { - this.canvas.add(rect) + this.addWithUpdate(rect) } } } @@ -204,7 +150,7 @@ export default class QPolygon extends fabric.Polygon { } inPolygon(point) { - const vertices = this.points + const vertices = this.getCurrentPoints() let intersects = 0 for (let i = 0; i < vertices.length; i++) { @@ -236,4 +182,57 @@ export default class QPolygon extends fabric.Polygon { return intersects % 2 === 1 } + + #distanceFromEdge(point) { + const vertices = this.getCurrentPoints() + let minDistance = Infinity + + for (let i = 0; i < vertices.length; i++) { + let vertex1 = vertices[i] + let vertex2 = vertices[(i + 1) % vertices.length] + + const dx = vertex2.x - vertex1.x + const dy = vertex2.y - vertex1.y + + const t = + ((point.x - vertex1.x) * dx + (point.y - vertex1.y) * dy) / + (dx * dx + dy * dy) + + let closestPoint + if (t < 0) { + closestPoint = vertex1 + } else if (t > 1) { + closestPoint = vertex2 + } else { + closestPoint = new fabric.Point(vertex1.x + t * dx, vertex1.y + t * dy) + } + + const distance = distanceBetweenPoints(point, closestPoint) + if (distance < minDistance) { + minDistance = distance + } + } + + return minDistance + } + + setViewLengthText(boolean) { + this.texts.forEach((text) => { + text.visible = boolean + }) + + this.canvas.renderAll() + } + + getCurrentPoints() { + const scaleX = this.scaleX + const scaleY = this.scaleY + + return this.points.map((point) => { + return { + x: point.x * scaleX, + y: point.y * scaleY, + } + }) + } } diff --git a/src/components/fabric/QPolygon2.js b/src/components/fabric/QPolygon2.js deleted file mode 100644 index b59356c6..00000000 --- a/src/components/fabric/QPolygon2.js +++ /dev/null @@ -1,79 +0,0 @@ -import { fabric } from 'fabric' - -export default class QPolygon2 extends fabric.Group { - type = 'QPolygon2' - polygon - points - texts = [] - canvas - constructor(points, options, canvas) { - const polygon = new fabric.Polygon(points, options) - super([polygon], {}) - this.points = points - this.polygon = polygon - this.canvas = canvas - - this.#init() - this.#addEvent() - } - - #init() { - this.#addLengthText() - } - - #addEvent() { - this.on('modified', () => { - // this.#addLengthText() - }) - } - - #addLengthText() { - const points = this.getCurrentPoints() - - points.forEach((start, i) => { - const end = points[(i + 1) % points.length] - const dx = end.x - start.x - const dy = end.y - start.y - const length = Math.sqrt(dx * dx + dy * dy) - - const midPoint = new fabric.Point( - (start.x + end.x) / 2, - (start.y + end.y) / 2, - ) - - if (this.texts[i]) { - // Update existing text - this.texts[i].set({ - text: length.toFixed(0), - left: midPoint.x, - top: midPoint.y, - }) - } else { - // Create new text object if it doesn't exist - const text = new fabric.Text(length.toFixed(0), { - left: midPoint.x, - top: midPoint.y, - fontSize: 16, - selectable: false, - }) - - this.texts.push(text) - this.addWithUpdate(text) - } - }) - - this.canvas.renderAll() - } - - getCurrentPoints() { - const scaleX = this.scaleX - const scaleY = this.scaleY - - return this.points.map((point) => { - return { - x: point.x * scaleX, - y: point.y * scaleY, - } - }) - } -} diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 88d50d4a..2016cb81 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -405,13 +405,17 @@ export function useMode() { }) // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다. - const polygon = new QPolygon(points, { - stroke: 'black', - fill: 'transparent', - viewLengthText: true, - selectable: true, - fontSize: fontSize, - }) + const polygon = new QPolygon( + points, + { + stroke: 'black', + fill: 'transparent', + viewLengthText: true, + selectable: true, + fontSize: fontSize, + }, + canvas, + ) // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) @@ -421,6 +425,7 @@ export function useMode() { polygon.fillCell() canvas.renderAll() polygon.setViewLengthText(false) + setMode(Mode.DEFAULT) } } From 74816e04030f187bd8829acee584f8de128f6540 Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 10:08:24 +0900 Subject: [PATCH 061/113] =?UTF-8?q?refactor:=20=EB=9D=BC=EC=9D=B8=208?= =?UTF-8?q?=EA=B0=9C=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EB=B6=84=EA=B8=B0?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 라인 6개 케이스와 겹치는 부분 분기 처리 스팀 팍팍 빠직빠직 --- src/hooks/useMode.js | 168 ++++++++++++++++++++++++++++++------------- 1 file changed, 120 insertions(+), 48 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 88d50d4a..9f20990f 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -456,12 +456,21 @@ export function useMode() { // 다름 라인이 오른쪽으로 이동 if (historyLines.current[i].direction === 'top') { if (prev.direction !== 'right') { - newOuterlines.push({ - x1: historyLines.current[i].x1 - 50, - y1: historyLines.current[i].y1 + 50, - x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 - 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 + 50, + } + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, @@ -473,12 +482,21 @@ export function useMode() { } else { // bottom if (prev?.direction !== 'right') { - newOuterlines.push({ - x1: historyLines.current[i].x1 - 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 + 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, @@ -491,12 +509,21 @@ export function useMode() { } else if (next.direction === 'left') { if (historyLines.current[i].direction === 'top') { if (prev?.direction !== 'left') { - newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 + 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 - 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, @@ -508,12 +535,21 @@ export function useMode() { } else { // bottom if (prev?.direction !== 'left') { - newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 + 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, @@ -526,12 +562,21 @@ export function useMode() { } else if (next.direction === 'top') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'top') { - newOuterlines.push({ - x1: historyLines.current[i].x1 - 50, - y1: historyLines.current[i].y1 + 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 + 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, @@ -543,12 +588,21 @@ export function useMode() { } else { // left if (prev?.direction !== 'top') { - newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 + 50, - x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 + 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, @@ -561,12 +615,21 @@ export function useMode() { } else if (next.direction === 'bottom') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'bottom') { - newOuterlines.push({ - x1: historyLines.current[i].x1 - 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 + 50, - y2: historyLines.current[i].y2 - 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, @@ -578,12 +641,21 @@ export function useMode() { } else { // left if (prev.direction !== 'bottom') { - newOuterlines.push({ - x1: historyLines.current[i].x1 + 50, - y1: historyLines.current[i].y1 - 50, - x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 - 50, - }) + if(historyLines.current.length === 6) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if(historyLines.current.length === 8) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 + 50, + }) + } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, From 5ec3840a5cca506e348c50e9c330ad4dde79180d Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 10:09:57 +0900 Subject: [PATCH 062/113] =?UTF-8?q?fix:=20=EC=98=A4=ED=83=80=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit syntax error 오타 수정 --- src/hooks/useMode.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 2c0de9c3..f181e251 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -461,20 +461,20 @@ export function useMode() { // 다름 라인이 오른쪽으로 이동 if (historyLines.current[i].direction === 'top') { if (prev.direction !== 'right') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, - } + }) } } else { newOuterlines.push({ @@ -487,14 +487,14 @@ export function useMode() { } else { // bottom if (prev?.direction !== 'right') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, @@ -514,14 +514,14 @@ export function useMode() { } else if (next.direction === 'left') { if (historyLines.current[i].direction === 'top') { if (prev?.direction !== 'left') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, @@ -540,14 +540,14 @@ export function useMode() { } else { // bottom if (prev?.direction !== 'left') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, @@ -567,14 +567,14 @@ export function useMode() { } else if (next.direction === 'top') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'top') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, @@ -593,14 +593,14 @@ export function useMode() { } else { // left if (prev?.direction !== 'top') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, @@ -620,14 +620,14 @@ export function useMode() { } else if (next.direction === 'bottom') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'bottom') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, @@ -646,14 +646,14 @@ export function useMode() { } else { // left if (prev.direction !== 'bottom') { - if(historyLines.current.length === 6) { + if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) - } else if(historyLines.current.length === 8) { + } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, From 4023a499c5dde3322ade93b3b1d6244ce857ae36 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 5 Jul 2024 10:17:38 +0900 Subject: [PATCH 063/113] =?UTF-8?q?=EC=95=88=EC=93=B0=EB=8A=94=EA=B1=B0=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 64 +++---------------------------- src/components/fabric/QPolygon.js | 2 +- 2 files changed, 6 insertions(+), 60 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index f17612a6..d4f11c7d 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -93,7 +93,6 @@ export default function Roof2() { ) canvas?.add(polygon) - console.log(polygon) polygon.fillCell({ width: 50, height: 30, padding: 10 }) } @@ -122,47 +121,7 @@ export default function Roof2() { canvasSizeMode() }, [verticalSize, horizontalSize]) - const addPolygonType1 = () => { - if (canvas) { - const polygon = new QPolygon( - [ - { x: 100, y: 100 }, - { x: 800, y: 100 }, - { x: 800, y: 800 }, - { x: 500, y: 800 }, - { x: 500, y: 400 }, - { x: 100, y: 400 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - }, - canvas, - ) - - canvas?.add(polygon) - - polygon.fillCell({ width: 20, height: 20, padding: 10 }) - } - } - - const rotate = () => { - const rect = canvas?.getObjects().find((obj) => obj.type === 'QRect') - if (!rect) { - alert('사각형을 먼저 만들어주세요.') - return - } - const angle = prompt('각도를 입력해주세요.', '0') - if (rect) { - rect.angle = parseInt(angle) - canvas?.renderAll() - } - } - - const makeQPolygon2 = () => { + const makeQPolygon = () => { if (canvas) { const polygon2 = new QPolygon( [ @@ -180,10 +139,11 @@ export default function Roof2() { selectable: true, fontSize: fontSize, }, - canvas, + canvas, // 필수로 넣어줘야 함 ) canvas?.add(polygon2) + console.log(polygon2) } } @@ -305,14 +265,6 @@ export default function Roof2() { > 점선 추가 - -
diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index c7dcf53c..75074ad8 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -8,6 +8,7 @@ export default class QPolygon extends fabric.Group { texts = [] canvas fontSize + qCells = [] constructor(points, options, canvas) { if (!options.fontSize) { throw new Error('Font size is required.') @@ -22,7 +23,6 @@ export default class QPolygon extends fabric.Group { this.points = points this.polygon = polygon this.canvas = canvas - this.#init() this.#addEvent() } From d8379dcfa2e4f464204f8a532d8f88c03ebe6888 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 5 Jul 2024 13:19:14 +0900 Subject: [PATCH 064/113] =?UTF-8?q?=EC=9D=B4=EC=A0=84=20line=EC=9D=98=20di?= =?UTF-8?q?rection=EC=9D=B4=20=EA=B0=99=EC=9D=80=20=EA=B2=BD=EC=9A=B0=20me?= =?UTF-8?q?rge,=20=EC=84=A0=ED=83=9D=ED=95=9C=20=EB=8F=84=ED=98=95=20?= =?UTF-8?q?=ED=9A=8C=EC=A0=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 34 +++++++++++++++++++++++++++++++--- src/hooks/useMode.js | 37 +++++++++++++++++++++++++++++++++---- src/store/canvasAtom.js | 2 +- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index d4f11c7d..07c5b86c 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -28,6 +28,8 @@ export default function Roof2() { // 글자크기 const [fontSize, setFontSize] = useRecoilState(fontSizeState) + const [angle, setAngle] = useState(0) + const { mode, changeMode, @@ -123,7 +125,7 @@ export default function Roof2() { const makeQPolygon = () => { if (canvas) { - const polygon2 = new QPolygon( + const polygon = new QPolygon( [ { x: 100, y: 100 }, { x: 800, y: 100 }, @@ -142,8 +144,18 @@ export default function Roof2() { canvas, // 필수로 넣어줘야 함 ) - canvas?.add(polygon2) - console.log(polygon2) + canvas?.add(polygon) + } + } + + const rotateShape = () => { + if (canvas) { + const activeObject = canvas?.getActiveObject() + + if (activeObject) { + activeObject.rotate(angle) + canvas?.renderAll() + } } } @@ -279,8 +291,24 @@ export default function Roof2() { > QPolygon +
+
+ +
{ + if ( + historyLines.current.length > 0 && + historyLines.current[historyLines.current.length - 1].direction === + line.direction + ) { + // 같은 방향의 선이 두 번 연속으로 그려지면 이전 선을 제거하고, 새로운 선과 merge한다. + + const lastLine = historyLines.current.pop() + canvas?.remove(lastLine) + + const mergedLine = new QLine( + [lastLine.x1, lastLine.y1, line.x2, line.y2], + { + stroke: 'black', + strokeWidth: 2, + selectable: false, + viewLengthText: true, + direction: lastLine.direction, + fontSize: fontSize, + }, + ) + historyLines.current.push(mergedLine) + canvas?.add(mergedLine) + } else { + historyLines.current.push(line) + canvas?.add(line) + } + } + const templateMode = () => { changeMode(canvas, Mode.EDIT) @@ -343,9 +373,8 @@ export function useMode() { direction: getDirection(a, b), fontSize: fontSize, }) - historyLines.current.push(line) + pushHistoryLine(line) - canvas?.add(line) canvas?.renderAll() } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 4cdaaa32..4c66c5ff 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -7,7 +7,7 @@ export const textState = atom({ export const fontSizeState = atom({ key: 'fontSizeState', - default: 10, + default: 16, }) export const canvasSizeState = atom({ From 20f8c30bd5e47aa283d1f20bc51d33a9c8010e96 Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 13:42:01 +0900 Subject: [PATCH 065/113] =?UTF-8?q?refactor:=20=EB=9D=BC=EC=9D=B84?= =?UTF-8?q?=EA=B0=9C=20=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 징글징글 --- src/hooks/useMode.js | 73 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 65 insertions(+), 8 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index afa3320e..83967d1f 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -490,7 +490,14 @@ export function useMode() { // 다름 라인이 오른쪽으로 이동 if (historyLines.current[i].direction === 'top') { if (prev.direction !== 'right') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, @@ -516,7 +523,14 @@ export function useMode() { } else { // bottom if (prev?.direction !== 'right') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, @@ -543,7 +557,14 @@ export function useMode() { } else if (next.direction === 'left') { if (historyLines.current[i].direction === 'top') { if (prev?.direction !== 'left') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, @@ -569,7 +590,14 @@ export function useMode() { } else { // bottom if (prev?.direction !== 'left') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, @@ -596,7 +624,14 @@ export function useMode() { } else if (next.direction === 'top') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'top') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, @@ -622,7 +657,14 @@ export function useMode() { } else { // left if (prev?.direction !== 'top') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 + 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 + 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, @@ -649,7 +691,14 @@ export function useMode() { } else if (next.direction === 'bottom') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'bottom') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 - 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, @@ -675,7 +724,14 @@ export function useMode() { } else { // left if (prev.direction !== 'bottom') { - if (historyLines.current.length === 6) { + if (historyLines.current.length === 4) { + newOuterlines.push({ + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 - 50, + y2: historyLines.current[i].y2 - 50, + }) + } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, @@ -711,6 +767,7 @@ export function useMode() { } } + console.log(newOuterlines) makePolygon(newOuterlines) } From 1d15c1917c6de906a98e609bb0114b4dcb93abdd Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 5 Jul 2024 14:28:16 +0900 Subject: [PATCH 066/113] =?UTF-8?q?4=EA=B0=81=20=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=EB=8F=84=ED=98=95=EB=B2=88=ED=98=B8=20=EB=A7=A4=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 71 ++++++++++++++++++----------------------- src/util/canvas-util.js | 28 ++++++++++++++++ 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 83967d1f..77a31e4b 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1,8 +1,8 @@ -import { useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import QLine from '@/components/fabric/QLine' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' -import { getStartIndex, rearrangeArray } from '@/util/canvas-util' +import { getStartIndex, rearrangeArray, findTopTwoIndexesByDistance } from '@/util/canvas-util' import { useRecoilState } from 'recoil' import { fontSizeState } from '@/store/canvasAtom' @@ -23,6 +23,7 @@ export function useMode() { const [canvas, setCanvas] = useState(null) const [zoom, setZoom] = useState(100) const [fontSize] = useRecoilState(fontSizeState) + const [shape, setShape] = useState(0) const addEvent = (mode) => { switch (mode) { @@ -381,47 +382,37 @@ export function useMode() { const makePolygon = (otherLines) => { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current - if (!otherLines) { + if (!otherLines) { //외각선 기준 const sortedIndex = getStartIndex(lines) - const tmpArraySorted = rearrangeArray(lines, sortedIndex) - - function findTopTwoIndexesByDistance(objArr) { - if (objArr.length < 2) { - return [] // 배열의 길이가 2보다 작으면 빈 배열 반환 - } - - let firstIndex = -1 - let secondIndex = -1 - let firstDistance = -Infinity - let secondDistance = -Infinity - - for (let i = 0; i < objArr.length; i++) { - const distance = objArr[i].length - - if (distance > firstDistance) { - secondDistance = firstDistance - secondIndex = firstIndex - firstDistance = distance - firstIndex = i - } else if (distance > secondDistance) { - secondDistance = distance - secondIndex = i - } - } - - return [firstIndex, secondIndex] + let tmpArraySorted = rearrangeArray(lines, sortedIndex) + + if(tmpArraySorted[0].direction === 'right') { //시계방향 + tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 } - const topIndex = findTopTwoIndexesByDistance(tmpArraySorted) - - let shape = 0 - - if (topIndex[0] === 2) { - if (topIndex[1] === 3) shape = 1 - } else if (topIndex === 1) { - if (topIndex[1] === 2) shape = 4 + const topIndex = findTopTwoIndexesByDistance(tmpArraySorted) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 + + //일단 배열 6개 짜리 기준의 선 번호 + if (topIndex[0] === 4) { + if (topIndex[1] === 5){ //1번 + setShape(1) + console.log('shape :: ', 1) + } + } else if (topIndex[0] === 1) { //4번 + if (topIndex[1] === 2){ + console.log('shape :: ', 4) + setShape(4) + } + }else if (topIndex[0] === 0) { + if(topIndex[1] === 1) { //2번 + console.log('shape :: ', 2) + setShape(2) + }else if(topIndex[1] === 5){ + console.log('shape :: ', 3) + setShape(3) + } } - + historyLines.current = [] } @@ -457,7 +448,7 @@ export function useMode() { setMode(Mode.DEFAULT) } } - + /** * 해당 캔버스를 비운다. */ diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index cd32d081..ca66ef48 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -177,3 +177,31 @@ export const rearrangeArray = (array, index) => { // 두 부분을 concat 메소드를 이용해 합칩니다. return fromIndexToEnd.concat(fromStartToIndex) } + + +export const findTopTwoIndexesByDistance = (objArr) => { + if (objArr.length < 2) { + return [] // 배열의 길이가 2보다 작으면 빈 배열 반환 + } + + let firstIndex = -1 + let secondIndex = -1 + let firstDistance = -Infinity + let secondDistance = -Infinity + + for (let i = 0; i < objArr.length; i++) { + const distance = objArr[i].length + + if (distance > firstDistance) { + secondDistance = firstDistance + secondIndex = firstIndex + firstDistance = distance + firstIndex = i + } else if (distance > secondDistance) { + secondDistance = distance + secondIndex = i + } + } + + return [firstIndex, secondIndex] +} \ No newline at end of file From 394136af4cf5f7ccbfa5ddf41a064c71a16641ee Mon Sep 17 00:00:00 2001 From: nalpari Date: Fri, 5 Jul 2024 14:36:25 +0900 Subject: [PATCH 067/113] =?UTF-8?q?fix:=20=EB=B0=98=EC=8B=9C=EA=B3=84=206?= =?UTF-8?q?=EA=B0=81=ED=98=95=20=EA=B3=84=EC=82=B0=20=EB=B2=84=EA=B7=B8=20?= =?UTF-8?q?=ED=94=BD=EC=8A=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 77a31e4b..63b4333b 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -572,10 +572,10 @@ export function useMode() { } } else { newOuterlines.push({ - x1: historyLines.current[i].x1 - 50, - y1: historyLines.current[i].y1 + 50, - x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 + 50, + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, }) } } else { @@ -672,10 +672,10 @@ export function useMode() { } } else { newOuterlines.push({ - x1: historyLines.current[i].x1 - 50, - y1: historyLines.current[i].y1 + 50, - x2: historyLines.current[i].x2 - 50, - y2: historyLines.current[i].y2 + 50, + x1: historyLines.current[i].x1 + 50, + y1: historyLines.current[i].y1 - 50, + x2: historyLines.current[i].x2 + 50, + y2: historyLines.current[i].y2 - 50, }) } } From f6b586cb778a6efe7fc6d75d19338392065cc152 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 5 Jul 2024 16:56:02 +0900 Subject: [PATCH 068/113] =?UTF-8?q?=EC=9A=B0=EC=84=A0=20=EC=BB=A8=ED=8A=B8?= =?UTF-8?q?=EB=A1=A4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 75074ad8..0a470587 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -19,10 +19,12 @@ export default class QPolygon extends fabric.Group { const polygon = new fabric.Polygon(points, options) super([polygon], {}) + this.fontSize = options.fontSize this.points = points this.polygon = polygon this.canvas = canvas + this.#init() this.#addEvent() } @@ -35,6 +37,11 @@ export default class QPolygon extends fabric.Group { this.on('scaling', (e) => { this.#updateLengthText() }) + + this.on('selected', function () { + // 모든 컨트롤 떼기 + this.controls = [] + }) } setFontSize(fontSize) { From 45b4b37e9636af909c55a82bda35ec23a5b7e588 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 5 Jul 2024 17:06:55 +0900 Subject: [PATCH 069/113] =?UTF-8?q?=EC=9D=B4=EA=B1=B0=EA=B5=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 0a470587..ed879b8b 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -45,11 +45,11 @@ export default class QPolygon extends fabric.Group { } setFontSize(fontSize) { + this.fontSize = fontSize this.texts.forEach((text) => { text.set({ fontSize }) - this.canvas.requestRenderAll() }) - this.fontSize = fontSize + this.addWithUpdate() } #addLengthText() { From fbc519573b1dd90deee1aa11eaaf2779126bdb56 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 8 Jul 2024 10:07:31 +0900 Subject: [PATCH 070/113] =?UTF-8?q?=EC=9A=B0=EC=84=A0=20=ED=9A=8C=EC=A0=84?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index ed879b8b..a13a69d6 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -40,7 +40,12 @@ export default class QPolygon extends fabric.Group { this.on('selected', function () { // 모든 컨트롤 떼기 - this.controls = [] + + Object.keys(this.controls).forEach((controlKey) => { + if (controlKey !== 'mtr') { + this.setControlVisible(controlKey, false) + } + }) }) } From e3bff53c09334c8d0202bd542704d14082fe803c Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 8 Jul 2024 10:41:35 +0900 Subject: [PATCH 071/113] =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=EB=B0=B0=EC=97=B4?= =?UTF-8?q?=20=EB=A6=AC=EC=BD=94=EC=9D=BC=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 9 +++++++-- src/hooks/useMode.js | 9 ++++++--- src/store/canvasAtom.js | 6 ++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 07c5b86c..fb08313f 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -6,8 +6,8 @@ import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' import RangeSlider from './ui/RangeSlider' -import { useRecoilState } from 'recoil' -import { canvasSizeState, fontSizeState } from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue } from 'recoil' +import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' export default function Roof2() { const { @@ -28,6 +28,8 @@ export default function Roof2() { // 글자크기 const [fontSize, setFontSize] = useRecoilState(fontSizeState) + const [sortedArray] = useRecoilState(sortedPolygonArray) + const [angle, setAngle] = useState(0) const { @@ -121,6 +123,9 @@ export default function Roof2() { */ useEffect(() => { canvasSizeMode() + + console.log('sortedArray', sortedArray) + }, [verticalSize, horizontalSize]) const makeQPolygon = () => { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 63b4333b..4b791ce6 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -4,7 +4,7 @@ import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' import { getStartIndex, rearrangeArray, findTopTwoIndexesByDistance } from '@/util/canvas-util' import { useRecoilState } from 'recoil' -import { fontSizeState } from '@/store/canvasAtom' +import { fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 @@ -24,6 +24,7 @@ export function useMode() { const [zoom, setZoom] = useState(100) const [fontSize] = useRecoilState(fontSizeState) const [shape, setShape] = useState(0) + const [sortedArray, setSortedArray] = useRecoilState(sortedPolygonArray) const addEvent = (mode) => { switch (mode) { @@ -388,10 +389,12 @@ export function useMode() { if(tmpArraySorted[0].direction === 'right') { //시계방향 tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 + } + setSortedArray(tmpArraySorted) //recoil에 넣음 const topIndex = findTopTwoIndexesByDistance(tmpArraySorted) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 - + //일단 배열 6개 짜리 기준의 선 번호 if (topIndex[0] === 4) { if (topIndex[1] === 5){ //1번 @@ -448,7 +451,7 @@ export function useMode() { setMode(Mode.DEFAULT) } } - + /** * 해당 캔버스를 비운다. */ diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 4c66c5ff..c4b5dd19 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -17,3 +17,9 @@ export const canvasSizeState = atom({ horizontal: 1000, }, }) + +export const sortedPolygonArray = atom({ + key: 'sortedArray', + default : [], + dangerouslyAllowMutability: true, +}) From 5e548210bc87aa207da82ef5a21b9b5b30ba2551 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 8 Jul 2024 10:42:31 +0900 Subject: [PATCH 072/113] =?UTF-8?q?=EC=A0=95=EB=A0=AC=20=EB=B0=B0=EC=97=B4?= =?UTF-8?q?=20=EB=A6=AC=EC=BD=94=EC=9D=BC=20console.log=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index fb08313f..9ee82c4e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -123,9 +123,6 @@ export default function Roof2() { */ useEffect(() => { canvasSizeMode() - - console.log('sortedArray', sortedArray) - }, [verticalSize, horizontalSize]) const makeQPolygon = () => { From 002a895910cfce93a35f2cc42f4baf3825e58414 Mon Sep 17 00:00:00 2001 From: nalpari Date: Mon, 8 Jul 2024 10:59:49 +0900 Subject: [PATCH 073/113] =?UTF-8?q?refactor:=20=ED=94=84=EB=A6=AC=ED=8B=B0?= =?UTF-8?q?=EC=96=B4=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 4b791ce6..90366ce4 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -2,7 +2,11 @@ import { useEffect, useRef, useState } from 'react' import QLine from '@/components/fabric/QLine' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' -import { getStartIndex, rearrangeArray, findTopTwoIndexesByDistance } from '@/util/canvas-util' +import { + getStartIndex, + rearrangeArray, + findTopTwoIndexesByDistance, +} from '@/util/canvas-util' import { useRecoilState } from 'recoil' import { fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' @@ -383,39 +387,43 @@ export function useMode() { const makePolygon = (otherLines) => { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current - if (!otherLines) { //외각선 기준 + if (!otherLines) { + //외각선 기준 const sortedIndex = getStartIndex(lines) let tmpArraySorted = rearrangeArray(lines, sortedIndex) - - if(tmpArraySorted[0].direction === 'right') { //시계방향 + + if (tmpArraySorted[0].direction === 'right') { + //시계방향 tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 - } setSortedArray(tmpArraySorted) //recoil에 넣음 const topIndex = findTopTwoIndexesByDistance(tmpArraySorted) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 //일단 배열 6개 짜리 기준의 선 번호 - if (topIndex[0] === 4) { - if (topIndex[1] === 5){ //1번 + if (topIndex[0] === 4) { + if (topIndex[1] === 5) { + //1번 setShape(1) console.log('shape :: ', 1) - } - } else if (topIndex[0] === 1) { //4번 - if (topIndex[1] === 2){ + } + } else if (topIndex[0] === 1) { + //4번 + if (topIndex[1] === 2) { console.log('shape :: ', 4) setShape(4) - } - }else if (topIndex[0] === 0) { - if(topIndex[1] === 1) { //2번 + } + } else if (topIndex[0] === 0) { + if (topIndex[1] === 1) { + //2번 console.log('shape :: ', 2) setShape(2) - }else if(topIndex[1] === 5){ + } else if (topIndex[1] === 5) { console.log('shape :: ', 3) setShape(3) } } - + historyLines.current = [] } From d0541b161da2f784b52f94f8af32a5fd643aaafa Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 8 Jul 2024 12:58:38 +0900 Subject: [PATCH 074/113] =?UTF-8?q?=ED=95=84=EC=9A=94=20=EC=97=86=EB=8A=94?= =?UTF-8?q?=20=EB=82=B4=EC=9A=A9=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useCanvas.js | 2 -- src/hooks/useMode.js | 32 -------------------------------- 2 files changed, 34 deletions(-) diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 9d860234..f1b98031 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -176,7 +176,6 @@ export function useCanvas(id) { strokeWidth: 1, selectable: false, name: 'mouseLine', - strokeDashArray: [5, 5], }, ) @@ -188,7 +187,6 @@ export function useCanvas(id) { strokeWidth: 1, selectable: false, name: 'mouseLine', - strokeDashArray: [5, 5], }, ) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 90366ce4..256b4968 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -62,38 +62,6 @@ export function useMode() { } const editMode = () => { - let distanceText = null // 거리를 표시하는 텍스트 객체를 저장할 변수 - canvas?.on('mouse:move', function (options) { - const pointer = canvas?.getPointer(options.e) - - if (historyLines.current.length === 0) return - const direction = getDirection(historyLines.current[0], pointer) - - // 각 선과 마우스 위치 사이의 거리를 계산합니다. - const dx = historyLines.current[0].x1 - pointer.x - const dy = 0 - - const minDistance = Math.sqrt(dx * dx + dy * dy) - - // 거리를 표시하는 텍스트 객체를 생성하거나 업데이트합니다. - if (distanceText) { - distanceText.set({ - left: pointer.x, - top: pointer.y, - text: `${minDistance.toFixed(2)}`, - }) - } else { - distanceText = new fabric.Text(`${minDistance.toFixed(2)}`, { - left: pointer.x, - top: pointer.y, - fontSize: fontSize, - }) - canvas?.add(distanceText) - } - - // 캔버스를 다시 그립니다. - canvas?.renderAll() - }) canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) const circle = new fabric.Circle({ From 845a469d4328ed57a3233fb7943d3f881dee150f Mon Sep 17 00:00:00 2001 From: nalpari Date: Mon, 8 Jul 2024 13:17:40 +0900 Subject: [PATCH 075/113] Auto stash before rebase of "feature/ui-add" onto "feature/test" --- package.json | 2 + src/app/UIProvider.js | 5 + src/app/layout.js | 5 +- src/components/Roof2.jsx | 46 +- tailwind.config.js | 20 +- yarn.lock | 2086 +++++++++++++++++++++++++++++++++++++- 6 files changed, 2123 insertions(+), 41 deletions(-) create mode 100644 src/app/UIProvider.js diff --git a/package.json b/package.json index 468b23e1..78ce1907 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "lint": "next lint" }, "dependencies": { + "@nextui-org/react": "^2.4.2", "fabric": "^5.3.0", + "framer-motion": "^11.2.13", "next": "14.2.3", "react": "^18", "react-dom": "^18", diff --git a/src/app/UIProvider.js b/src/app/UIProvider.js new file mode 100644 index 00000000..02a21441 --- /dev/null +++ b/src/app/UIProvider.js @@ -0,0 +1,5 @@ +import { NextUIProvider } from '@nextui-org/react' + +export default function UIProvider({ children }) { + return {children} +} diff --git a/src/app/layout.js b/src/app/layout.js index 84095436..156536aa 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -2,6 +2,7 @@ import { Inter } from 'next/font/google' import './globals.css' import Headers from '@/components/Headers' import RecoilRootWrapper from './RecoilWrapper' +import UIProvider from './UIProvider' const inter = Inter({ subsets: ['latin'] }) @@ -15,7 +16,9 @@ export default function RootLayout({ children }) { - {children} + + {children} + ) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 9ee82c4e..77a5fd38 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -7,7 +7,11 @@ import QPolygon from '@/components/fabric/QPolygon' import RangeSlider from './ui/RangeSlider' import { useRecoilState, useRecoilValue } from 'recoil' -import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' +import { + canvasSizeState, + fontSizeState, + sortedPolygonArray, +} from '@/store/canvasAtom' export default function Roof2() { const { @@ -165,9 +169,9 @@ export default function Roof2() { <> {canvas && ( <> -
+
현재 줌 : {zoom}% - - - - - - + - + - + - + - + + 현재 줌 : {zoom}% - - + - + - - - + - + - + +
From 864e892a7dd8820ace9ff2d76f0c87e0d101af71 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 8 Jul 2024 14:17:26 +0900 Subject: [PATCH 077/113] =?UTF-8?q?QLine=20=EA=B7=B8=EB=A3=B9=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 20 +++++- src/components/fabric/QLine.js | 108 +++++++++++++++++---------------- src/hooks/useMode.js | 2 +- 3 files changed, 77 insertions(+), 53 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 77a5fd38..ffd2e005 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -2,7 +2,6 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEffect, useState } from 'react' import { Mode, useMode } from '@/hooks/useMode' import QRect from '@/components/fabric/QRect' -import QLine from '@/components/fabric/QLine' import QPolygon from '@/components/fabric/QPolygon' import RangeSlider from './ui/RangeSlider' @@ -12,6 +11,7 @@ import { fontSizeState, sortedPolygonArray, } from '@/store/canvasAtom' +import { QLine } from '@/components/fabric/QLine' export default function Roof2() { const { @@ -165,6 +165,18 @@ export default function Roof2() { } } + const makeQLine = () => { + if (canvas) { + const line = new QLine([50, 50, 200, 50], { + stroke: 'black', + strokeWidth: 2, + fontSize: fontSize, + }) + + canvas?.add(line) + } + } + return ( <> {canvas && ( @@ -303,6 +315,12 @@ export default function Roof2() { > 회전 +
diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index a5d63c83..667fe213 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -1,27 +1,39 @@ import { fabric } from 'fabric' -export default class QLine extends fabric.Line { +export class QLine extends fabric.Group { + line + text + fontSize length - #text - #viewLengthText - #fontSize + x1 + y1 + x2 + y2 + direction type = 'QLine' + constructor(points, option) { + const [x1, y1, x2, y2] = points + if (!option.fontSize) { throw new Error('Font size is required.') } - super(points, option) - this.#fontSize = option.fontSize - this.#init(option) + const line = new fabric.Line(points, { ...option, strokeWidth: 1 }) + super([line], {}) + + this.x1 = x1 + this.y1 = y1 + this.x2 = x2 + this.y2 = y2 + this.line = line + this.fontSize = option.fontSize + this.direction = option.direction + this.#init() this.#addControl() } - #init(option) { - // 선의 길이를 계산하여 length 속성을 초기화합니다. - const dx = this.x2 - this.x1 - const dy = this.y2 - this.y1 - this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) - this.#viewLengthText = option.viewLengthText ?? true + #init() { + this.#addLengthText() } #addControl() { @@ -34,52 +46,46 @@ export default class QLine extends fabric.Line { }) this.on('modified', (e) => { - const scaleX = this.scaleX - const scaleY = this.scaleY - - // x1, y1, x2, y2 속성을 새로운 좌표로 설정합니다. - this.x1 = this.left - this.y1 = this.top - this.x2 = this.left + this.width * scaleX - this.y2 = this.top + this.height * scaleY - - const dx = this.x2 - this.x1 - const dy = this.y2 - this.y1 - const length = Math.sqrt(dx * dx + dy * dy) - this.length = Number(length.toFixed(0)) // 선의 길이를 length 속성에 저장합니다. this.#addLengthText() }) - this.on('removed', () => { - this.canvas.remove(this.#text) - this.#text = null + this.on('selected', () => { + Object.keys(this.controls).forEach((controlKey) => { + if (controlKey !== 'ml' && controlKey !== 'mr') { + this.setControlVisible(controlKey, false) + } + }) }) } - setViewLengthText(bool) { - this.#viewLengthText = bool - this.#addLengthText() + #addLengthText() { + if (this.text) { + this.removeWithUpdate(this.text) + this.text = null + } + + const scaleX = this.scaleX + const scaleY = this.scaleY + const x1 = this.left + const y1 = this.top + const x2 = this.left + this.width * scaleX + const y2 = this.top + this.height * scaleY + const dx = x2 - x1 + const dy = y2 - y1 + this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) + + const text = new fabric.Textbox(this.length.toString(), { + left: (x1 + x2) / 2, + top: (y1 + y2) / 2, + fontSize: this.fontSize, + }) + this.text = text + this.addWithUpdate(text) } setFontSize(fontSize) { - this.#fontSize = fontSize - this.#addLengthText() - } - - #addLengthText() { - if (this.#text) { - this.canvas.remove(this.#text) - } - - if (this.#viewLengthText) { - const text = new fabric.Text(this.length.toString(), { - left: (this.x1 + this.x2) / 2, - top: (this.y1 + this.y2) / 2, - fontSize: this.#fontSize, - selectable: false, - }) - this.#text = text - this.canvas.add(text) - } + this.fontSize = fontSize + this.text.set({ fontSize }) + this.addWithUpdate() } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 256b4968..a44b0407 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1,5 +1,4 @@ import { useEffect, useRef, useState } from 'react' -import QLine from '@/components/fabric/QLine' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' import { @@ -9,6 +8,7 @@ import { } from '@/util/canvas-util' import { useRecoilState } from 'recoil' import { fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' +import { QLine } from '@/components/fabric/QLine' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 From 6fedf95383519495dce8bed3bbf837869cffb87b Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 8 Jul 2024 15:05:52 +0900 Subject: [PATCH 078/113] =?UTF-8?q?=EC=99=B8=EA=B3=BD=EC=84=A0=20=EA=B7=B8?= =?UTF-8?q?=EB=A6=AC=EA=B8=B0=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 68 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 63 insertions(+), 5 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index a44b0407..ebcaa5c5 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -206,7 +206,8 @@ export function useMode() { points.current = [] historyPoints.current = [] - handleOuterlines() + // handleOuterlines() + handleOuterlinesTest() //외곽선 그리기 테스트 makePolygon() } @@ -355,6 +356,7 @@ export function useMode() { const makePolygon = (otherLines) => { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current + if (!otherLines) { //외각선 기준 const sortedIndex = getStartIndex(lines) @@ -373,21 +375,17 @@ export function useMode() { if (topIndex[1] === 5) { //1번 setShape(1) - console.log('shape :: ', 1) } } else if (topIndex[0] === 1) { //4번 if (topIndex[1] === 2) { - console.log('shape :: ', 4) setShape(4) } } else if (topIndex[0] === 0) { if (topIndex[1] === 1) { //2번 - console.log('shape :: ', 2) setShape(2) } else if (topIndex[1] === 5) { - console.log('shape :: ', 3) setShape(3) } } @@ -741,6 +739,66 @@ export function useMode() { makePolygon(newOuterlines) } + const handleOuterlinesTest = () => { + var offsetPoints = [] + let offset = -35.5 // == 100 - 29 + + const points = historyLines.current.map((line) => ({ + x: line.x1, + y: line.y1, + })) + + for (var i = 0; i < points.length; i++) { + var prev = points[(i - 1 + points.length) % points.length] + var current = points[i] + var next = points[(i + 1) % points.length] + + // 두 벡터 계산 (prev -> current, current -> next) + var vector1 = { x: current.x - prev.x, y: current.y - prev.y } + var vector2 = { x: next.x - current.x, y: next.y - current.y } + + // 벡터의 길이 계산 + var length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) + var length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) + + // 벡터를 단위 벡터로 정규화 + var unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } + var unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } + + // 법선 벡터 계산 (왼쪽 방향) + var normal1 = { x: -unitVector1.y, y: unitVector1.x } + var normal2 = { x: -unitVector2.y, y: unitVector2.x } + + // 법선 벡터 평균 계산 + var averageNormal = { + x: (normal1.x + normal2.x) / 2, + y: (normal1.y + normal2.y) / 2, + } + + // 평균 법선 벡터를 단위 벡터로 정규화 + var lengthNormal = Math.sqrt( + averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y, + ) + var unitNormal = { + x: averageNormal.x / lengthNormal, + y: averageNormal.y / lengthNormal, + } + + console.log('current', current) + console.log('unitNormal', unitNormal) + + // 오프셋 적용 + var offsetPoint = { + x1: current.x + unitNormal.x * offset, + y1: current.y + unitNormal.y * offset, + } + + offsetPoints.push(offsetPoint) + } + + makePolygon(offsetPoints) + } + return { mode, changeMode, From f5cd2d6e38775d77dd79e64cf521fd19e33442ad Mon Sep 17 00:00:00 2001 From: nalpari Date: Mon, 8 Jul 2024 15:15:24 +0900 Subject: [PATCH 079/113] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 디비 연동 대기 --- src/app/layout.js | 7 +++- src/app/login/page.jsx | 91 ++++++++++++++++++++++++++++++++++++++++++ src/middleware.js | 12 ++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 src/app/login/page.jsx create mode 100644 src/middleware.js diff --git a/src/app/layout.js b/src/app/layout.js index 156536aa..55cb11f3 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -3,6 +3,7 @@ import './globals.css' import Headers from '@/components/Headers' import RecoilRootWrapper from './RecoilWrapper' import UIProvider from './UIProvider' +import { headers } from 'next/headers' const inter = Inter({ subsets: ['latin'] }) @@ -12,10 +13,14 @@ export const metadata = { } export default function RootLayout({ children }) { + const headersList = headers() + const headerPathname = headersList.get('x-pathname') || '' + // console.log('headerPathname', headerPathname) + return ( - + {headerPathname !== '/login' && } {children} diff --git a/src/app/login/page.jsx b/src/app/login/page.jsx new file mode 100644 index 00000000..c5d063fd --- /dev/null +++ b/src/app/login/page.jsx @@ -0,0 +1,91 @@ +export default function page() { + return ( + <> +
+
+
+ Your Company +

+ Sign in to your account +

+
+ +
+
+
+ +
+ +
+
+ +
+
+ + +
+
+ +
+
+ +
+ +
+
+ +

+ Not a member?{' '} + + Start a 14 day free trial + +

+
+
+
+ + ) +} diff --git a/src/middleware.js b/src/middleware.js new file mode 100644 index 00000000..d0329940 --- /dev/null +++ b/src/middleware.js @@ -0,0 +1,12 @@ +import { NextRequest, NextResponse } from 'next/server' + +export function middleware(request) { + const requestHeaders = new Headers(request.headers) + requestHeaders.set('x-pathname', request.nextUrl.pathname) + + return NextResponse.next({ + request: { + headers: requestHeaders, + }, + }) +} From 17d82d63db4be2ee24c42785bd47686f88d83672 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 8 Jul 2024 15:52:34 +0900 Subject: [PATCH 080/113] =?UTF-8?q?QPolygon=EC=97=90=20=EC=99=B8=EA=B3=BD?= =?UTF-8?q?=EC=84=A0=20=EA=B7=B8=EB=A6=AC=EA=B8=B0=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?(=ED=95=84=EC=9A=94=EC=97=86=EC=9C=BC=EB=A9=B4=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=EC=98=88=EC=A0=95)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 8 +++- src/components/fabric/QPolygon.js | 70 +++++++++++++++++++++++++++++++ src/hooks/useMode.js | 1 + 3 files changed, 77 insertions(+), 2 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index b2f9a022..0b6e30f7 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -144,7 +144,7 @@ export default function Roof2() { { fill: 'transparent', stroke: 'black', - strokeWidth: 2, + strokeWidth: 1, selectable: true, fontSize: fontSize, }, @@ -152,6 +152,10 @@ export default function Roof2() { ) canvas?.add(polygon) + + polygon.drawOuterLine(-50) + + console.log(polygon.outerPolygon) } } @@ -170,7 +174,7 @@ export default function Roof2() { if (canvas) { const line = new QLine([50, 50, 200, 50], { stroke: 'black', - strokeWidth: 2, + strokeWidth: 1, fontSize: fontSize, }) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index a13a69d6..cc8bbce8 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -9,6 +9,7 @@ export default class QPolygon extends fabric.Group { canvas fontSize qCells = [] + outerPolygon constructor(points, options, canvas) { if (!options.fontSize) { throw new Error('Font size is required.') @@ -247,4 +248,73 @@ export default class QPolygon extends fabric.Group { } }) } + + /** + * 외곽선 그리기 + * @param offset + */ + drawOuterLine(offset = -10) { + const points = this.getCurrentPoints() + const offsetPoints = [] + for (let i = 0; i < points.length; i++) { + const prev = points[(i - 1 + points.length) % points.length] + const current = points[i] + const next = points[(i + 1) % points.length] + + // 두 벡터 계산 (prev -> current, current -> next) + const vector1 = { x: current.x - prev.x, y: current.y - prev.y } + const vector2 = { x: next.x - current.x, y: next.y - current.y } + + // 벡터의 길이 계산 + const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) + const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) + + // 벡터를 단위 벡터로 정규화 + const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } + const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } + + // 법선 벡터 계산 (왼쪽 방향) + const normal1 = { x: -unitVector1.y, y: unitVector1.x } + const normal2 = { x: -unitVector2.y, y: unitVector2.x } + + // 법선 벡터 평균 계산 + const averageNormal = { + x: (normal1.x + normal2.x) / 2, + y: (normal1.y + normal2.y) / 2, + } + + // 평균 법선 벡터를 단위 벡터로 정규화 + const lengthNormal = Math.sqrt( + averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y, + ) + const unitNormal = { + x: averageNormal.x / lengthNormal, + y: averageNormal.y / lengthNormal, + } + + // 오프셋 적용 + const offsetPoint = { + x: current.x + unitNormal.x * offset, + y: current.y + unitNormal.y * offset, + } + + offsetPoints.push(offsetPoint) + } + + const outPolygon = new QPolygon( + offsetPoints, + { + stroke: 'black', + strokeWidth: 1, + fill: 'transparent', + fontSize: this.fontSize, + }, + this.canvas, + ) + + this.outerPolygon = outPolygon + + this.addWithUpdate(outPolygon) + this.canvas.renderAll() + } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index ebcaa5c5..d2ebd3dd 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -416,6 +416,7 @@ export function useMode() { // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) + // polygon.drawOuterLine(50) // 캔버스를 다시 그립니다. if (!otherLines) { From a16e4cccba0a79245331ecf930fa5796d711b0a5 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 8 Jul 2024 16:44:08 +0900 Subject: [PATCH 081/113] =?UTF-8?q?polygon=20=EB=B0=B1=EA=B7=B8=EB=9D=BC?= =?UTF-8?q?=EC=9A=B4=EB=93=9C=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/assets/img/check.jpg | Bin 0 -> 5083 bytes src/components/Roof2.jsx | 15 +++++++++++++++ src/components/fabric/QPolygon.js | 7 ++++++- src/hooks/useCanvas.js | 7 +++++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 public/assets/img/check.jpg diff --git a/public/assets/img/check.jpg b/public/assets/img/check.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83c66d2f2917084e72db364fe6c2e9a413814e78 GIT binary patch literal 5083 zcmYjV2T+qs*AAdkZa_oPP`xNUfP|(H)Jq3xLLhVz2q8eIh9V+fHAD#kB@i$afdmK; ziWG^!MKmhXTL9@21unfPAYkE(-^~BbzwgYR-93BG%s%t%IcML)vBO!wi7OV?762X| z0Dy=40S+etIDinpfT*Y_SQI2K0RkNtl>i+-eq2I=+Z_i>NJ)al!C)DAO+^_w$Z0TG z>4FmE98^zFPf7vy7fkoErmh~82M7e7IDX??rW2%bf9@{-@;u$wPUK9ewYb98Lg$+;v_M9|&+6uq#?`TE2)yka}K0 zwQC1&V87~lN*fQFf84j95Fv;h0=ih{lP)^%rgh>7>7UjcKG8iW4*5=(+D51gJP-QH z<&+&5W;AJ7=z!)!CGrcKLhq9d(~CO)WMqJF%olR986 zdD%I@(m}(g z3E}3-Q4Ep!Y&kE2eA46E{R&!~ZTj}ug3#_Tq&X=7CAL;kUsmQ`*W4C22m^NAfA)Su zN;wHP=*i30nRaP#r}&V4jR!TBRhsOg-iZ8iB=vOA#2^x7>A#Z5IKO!5D36*xs4K?! zZ&J!9;3K+AA?N`n)5~&qocDU~L;bRheTxyzO0D-lR1aF_8aPi}9)V+3<+dK}pvxv= z^{ozmOp@SQh_|BTdmuj|`iT_wq>08ImIO4T?$5lsL4ovR?n(jQJxL&~q0X-8%(lnZ z1C~|V35p6(@af1pXw?CnY>V`LCrVCF755$6^Zr8++nuxc)^}`@nkbCKtIT|hv)!Yi zQc7AsXj&JrVD4ya-UX^tTav4pD0%1&)2m52x_K@=GSh8KHQv4)=U9iliW1$;yepjz${E3q;b4hr@$1OaDdl0$Cx{sE9o*}c%Jqj(dKtQ0L?!QWbRs9rdd%z)U{w{7 z;Rg)LVfX=$RF)1wS22}STC&mfk zARd}xD}tk}z8V%F2=$=UeAqi0K|&8l6O@+0waxqk6EIadoVyA&X{?5x`$A`*p;ntKkO zd|4BV>xa?m(qqN@PjoA+!>Fk7#H<61E-ZSpY$e+9K~T<@ZfdL?s;wbK-@w9{cAj0&DXOf#zOpppKJ5M^ep3Aaa-oa9bztKjW$C&hr4%rnw=}#3tTV5!?B|Hj zN?v=14uz?wV!60@NE_?eTZcQEcSbJU`6J83r(DdRF&KP?87i~YvlKemiOKVS73Fb;~)cW@rwSJ|E;M z2GQ%y`!c9*c^<}ec6)6QkZA3v6%g|=XV?~*8~Un$*pav}tCabSOVINcI>&f@$Z2(P zVHkS2O8bq7n&Leh;nd8k0$qPCUkB?p^OwTN7Q2~(GIaiWSjW>V0rziB7bpzMrxtv9 zMEAg+Z-locne2AOIwk?Hxb~CkpD02WxFj9h?Mlq3xW2GTStxB6v>6KTb*z+D@*$_b z2JiO8N+ksvyg+mT{R1H>Uxn7Mv$A@9S0v5*!amIC+P>Eh^5P!RtxdtBz0c<{0h@WA zDYej`xAw}u8v>pR%5S%^k!SKiP>l}d#~Y_UD2_=cI@&uvRHVso)(!uIrAi8MQ4g{4Bw3{y5E`f0nVn1w@px0mdvqqr|19(^h8SyQn{ZaG zy(ZA6o#3B^0$p5+W6oH{3ZgRm>FI^PZJcc~+PveXScV zr6nrf>F-Z>Gz}=JdHkf*<}^Hbb$icP^8<9V33*-Lpt1+qvx-G%;R8@e`D6+g_UwPN zLsK!h)xw3Z2YSvJP?DW^{t?t|!%C&gYR_rtZ;l!>-!mFTwkUh>U!do3XL~jOFQe^U zOto;aUsYn-;uXQpXH3Au2Mx{?;*Lc+Vv=)kx5L|e1v6JTF1>V@ z92ux;&YlaF+y5GxX&HiM78Eb%3A6Q1YG)WJO|b<`kv)|k2k;Q1wil4rx{6LA2~_CM z*X{!W@Xh(^0Vt|(xbs%3myguWlpw=BmvB}o3oMv} zEWh@B}nxh>Qh5L|mq?JNUqiG@8b1KlUC8_OJ?3;ZMQ_pi>iWhdaeR3Gy zYKbN(`Q3|cdZfazt)Io?Gp#r5Wm_FOtQ%rl7Eb0ldq@YwlT}jlf4a_9zK?2p;dC?q z661?K$PiJFN8MYr#BA8IA4GJqIOB@3@?4C+!r#@&zf3304b%_l5hj{uN0t%~lJ4PvGTBEL~79^&YoW^m? z>cWK$=dC}!*a>IoT!!QYI=H>))UgZL7s42@jr9Ar&wF@`3$gVCqDxX)Lu@W&5x2e5 z`h7A%@3ZIrtP?VJFXDUTPh}M4?YK($Y|YgAyFUS%t~?mRR8JKr@*vX}-7rF(&L=NRTD z{$EfHvmenWFw}kD{OJv=UV(u=BM+)1aVJJ-_t$W(G$Y!p!{SD_5y=dn$Y44r6Sqwj zZok8#9F<J(!*{R$w{(aW)vtSfIoV<#kRgN z8E)U^skh6m(aVyuqOHq09CxoXf|vVb}oD_=XEpLNIo7%G6@KBoWl zO+~~sdpZ!Qqp@M!ult=J*>5y@;b&87jboWBmq=M|7@e7JBUb&Bh)*NFr~?tquPtg! zW5v-2a_8Lo6$Zv4VH1^+-vvS`iwJz9jm(8WIf%?C{@JW@SjhS69q*(rpZ3HmSA{z+ z>IUR|B85^k7@}PB+WiR%iN+wF-E3y))rsj|y>YYP%8)GNhXkc>?zX-GjaTheOodZc zenn2HKeJ}@>f}so6vT7~q3_ZJk9$%uLZ!(l)`C|)Bv~o0Jh0*G+ z=Gcu*M+w6izGMowI2E~LUp}^!Gx1&_U3RppwpUN5d^SSI$Q&CHA*QlsHCkQkEi+^} zTLiDZPb`f~pvlObV+k3@vTBx9E2+LOoF2AS2^jdt}Y3+Ym1 zq7X!(JueuIz&Fe)p^Jpst*cQUQcFVYGg&(yFgJ|#Kb+lk)xgaO_4Gtu6k?>bO`SxY z`V=oK=55rAcqJm6dHh$j>cqdCakK10Kv;ztIp+TJFVxwX7J5+3h^TB;^@_dZ=)>!r zsb%u)=bs*$sL|7^exZJs)+Br{n-{KsH(4C}JpQNV^x}zBCP6+Uq+Z4$^u)vC^UWow zQRT*mMlIi?-TZy;7QCQ=Wq7^3?|w7D`YrwWIS>zQed%h+&$o8z1m0USuii$cjXM_e zl#Z0~ws`oCKagV?G&#e`vi_8f;TGMMVNxR6E3*|ZB%^;;4tVX`jC7x=v?=+JtxF#s z_q~74cjPKxT}U+emeX!Nd;^o&C<}Bg8-^I!)b$E9-?k`1N5;sKW=guk_)ot;6SX4M z!p?CY2x>YZV!x*C!jnzK_C1bWh;gSdANiA>O}xU+W$oxE2+ig0Yr4riEg)xsXP%3M z_?{*81Bte)h}U1E5$MPCPRH1AyS@Ol2pG|&IQ5I10i1y(WTwGJtAnc|+MCJ^-UKtv zKG6|@Af?dJ1OiB!*b_VQ1y-i6IR-dAnJZ*OpPErrvK(o-3*WRp-;uRe1(f|aXI zufiEc*d8KMa#~wyCqIkM)35s(H?&{kUw+wo~12)7!E#}{o*<* zeWgrll8DY{(&tqpxF9O|;}!@VOqo#AsOo_T@zMb6w0w-q1n2MktZ?rb{_Oc9lcu_e zR}Md^J#Tad#?imvq`r;^Qf`an{cMS%(kmjdKV5L}q?57c2DjBhtX+a&mfOYlhXCv< zA%>XQ!7S`wQxcteS}&;^rFxoOq@tVWtzk4xYaH-4_zv$ zi3p;sQLU;+nyDS7QQhVjYVBRa7zonbi;nMk#2aR9T@l(l`L3442vL){CWKfyy9;XD zB8_!Q67RZJph|7OAnCSu1=FN&bZxasDVYURIRwbhWHVTC>1iEg)<@4%S_8xfK0?*H zE8pEY<`)EgShWwMnu`LuY`O2#GLfbA(vHmR;^o|ZkK zNEdQP)gv_vW^^3{My%dmV2|qBiKxEq6b`rn8Dr?*r}lKPO9(Az@>B!tmf^ieKXycU z)oJ;~mudBkJ}@tQ#EN~bsN=2`r= zXdOa!uvXWO0jl&X?4YjG{hp8N8NnZmnf8z6q&9Ks#Em@!--ALM$$GPtuQ3|RVx9pc zx8kpis9u+Q+_(Fg{V;}ecLOxNMy$@_l6DP8M&Wj!om_`ki-1|zKSuQyQ1W8bT#hjJ z9$Sd6CMeG`gVrKlQ@A%4hDFd6v_5@{b2t%}){!6n?6GZ92*7DmIQ>y2P`hK;uSEE=ap|1y8l9u9muN&x4I~d$%#5fNW zm&N;-3?FGxUq8J)!Yf%EDyiBcT)o^Y-DR25%qHZ!|Lr?f90z7E54zm*?#g|82w<2| zu{7avH+dN%x@_>xfIQd^pS@Ll`T zCt{>IBs<`KP<#SS8VIaRP{tkkjSc3JDd+Mrl%qnp%?L-=v{{j)NV`>o8;nZ?iPVeT zv*2~ztX@@wl)u7oIW-5bD1UoUuinFQ+Rk_J#CMY1{GPHa3Z+X>&y{?$*@?k@Z-m_K z!CMvexE6(L^?6WwCAzE!s(rnHzU=vrZI;(;LBCS+#i zz{;1VsF7S8|uQ(cGmw3y=Lo zZzM$i!*uCRha1|QjvR^oK{(o-zQbNT1iUZY-FJ|FP`lX_)!Aw{Qxh?uneuv*Fi+k! z6mH&AYoES@uD1PjI~p9bD+^B(ZHgK=Df>ORayf?kui}HF-uL$8@#yZy!^HCS>IspD PnpWEZ-Pwxg4#)okch;W= literal 0 HcmV?d00001 diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 0b6e30f7..54216362 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -154,6 +154,7 @@ export default function Roof2() { canvas?.add(polygon) polygon.drawOuterLine(-50) + addBackgroundInPolygon(polygon) console.log(polygon.outerPolygon) } @@ -182,6 +183,20 @@ export default function Roof2() { } } + const addBackgroundInPolygon = (polygon) => { + fabric.Image.fromURL('assets/img/check.jpg', function (img) { + // 패턴 객체를 생성합니다. + const pattern = new fabric.Pattern({ + source: img.getElement(), + repeat: 'repeat', + }) + + polygon.fillBackground(pattern) + + console.log(polygon) + }) + } + return ( <> {canvas && ( diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index cc8bbce8..b20350b5 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -24,7 +24,7 @@ export default class QPolygon extends fabric.Group { this.fontSize = options.fontSize this.points = points this.polygon = polygon - this.canvas = canvas + // this.canvas = canvas this.#init() this.#addEvent() @@ -317,4 +317,9 @@ export default class QPolygon extends fabric.Group { this.addWithUpdate(outPolygon) this.canvas.renderAll() } + + fillBackground(pattern) { + this.polygon.set({ fill: pattern }) + this.canvas.renderAll() + } } diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index f1b98031..5f44060a 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -8,6 +8,9 @@ import { import { useRecoilState } from 'recoil' import { canvasSizeState, fontSizeState } from '@/store/canvasAtom' +import QPolygon from '@/components/fabric/QPolygon' +import { QLine } from '@/components/fabric/QLine' +import QRect from '@/components/fabric/QRect' export function useCanvas(id) { const [canvas, setCanvas] = useState() @@ -35,6 +38,10 @@ export function useCanvas(id) { fabric.Object.prototype.cornerStrokeColor = '#2BEBC8' fabric.Object.prototype.cornerSize = 6 + QPolygon.prototype.canvas = c + QLine.prototype.canvas = c + QRect.prototype.canvas = c + setCanvas(c) return () => { c.dispose() From 2963b26d6574bf2db8338b87c6d2b5606e88cc4e Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 8 Jul 2024 17:29:08 +0900 Subject: [PATCH 082/113] =?UTF-8?q?=EC=A7=80=EB=B6=95=EC=9E=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/assets/img/check2.png | Bin 0 -> 234 bytes src/components/Roof2.jsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 public/assets/img/check2.png diff --git a/public/assets/img/check2.png b/public/assets/img/check2.png new file mode 100644 index 0000000000000000000000000000000000000000..6abee7b1a0ab24e4086da8da28b80168bfb937cb GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^EQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`ISV`@iy0XB4ude`@%$AjK*4%X7srqc=eM^u3LY{LU~rrn^royKZsY5P zVjd>*J_a)FK3QM$`P7y*>wl*g>^gf=#Up0knctOX-tN!&ot&rlq+LPLgF~pPg+%J# hj8<+=N4;Y|m?9Q(E<1jzAPVRd22WQ%mvv4FO#p}uOu_&F literal 0 HcmV?d00001 diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 54216362..141db8de 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -184,7 +184,7 @@ export default function Roof2() { } const addBackgroundInPolygon = (polygon) => { - fabric.Image.fromURL('assets/img/check.jpg', function (img) { + fabric.Image.fromURL('assets/img/check2.png', function (img) { // 패턴 객체를 생성합니다. const pattern = new fabric.Pattern({ source: img.getElement(), From 3414f2ca3c352bba250ed04a1a97ad82f1a52690 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 9 Jul 2024 13:46:06 +0900 Subject: [PATCH 083/113] =?UTF-8?q?=EC=99=B8=EA=B3=BD=EC=84=A0=20=EC=88=9C?= =?UTF-8?q?=EC=84=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index d2ebd3dd..62a767a0 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -742,9 +742,17 @@ export function useMode() { const handleOuterlinesTest = () => { var offsetPoints = [] - let offset = -35.5 // == 100 - 29 + let offset = 71 // == 100 - 29 - const points = historyLines.current.map((line) => ({ + const sortedIndex = getStartIndex(historyLines.current) + let tmpArraySorted = rearrangeArray(historyLines.current, sortedIndex) + + if (tmpArraySorted[0].direction === 'right') { + //시계방향 + tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 + } + + const points = tmpArraySorted.map((line) => ({ x: line.x1, y: line.y1, })) @@ -785,9 +793,6 @@ export function useMode() { y: averageNormal.y / lengthNormal, } - console.log('current', current) - console.log('unitNormal', unitNormal) - // 오프셋 적용 var offsetPoint = { x1: current.x + unitNormal.x * offset, @@ -796,7 +801,7 @@ export function useMode() { offsetPoints.push(offsetPoint) } - + makePolygon(offsetPoints) } From 6c930f2e6e08e5454bc0b57e9e6b9c1856bd0fe5 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 9 Jul 2024 13:48:04 +0900 Subject: [PATCH 084/113] add polygonToLine --- src/hooks/useMode.js | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index d2ebd3dd..11c0fceb 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -416,7 +416,6 @@ export function useMode() { // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) - // polygon.drawOuterLine(50) // 캔버스를 다시 그립니다. if (!otherLines) { @@ -800,6 +799,42 @@ export function useMode() { makePolygon(offsetPoints) } + const togglePolygonLine = (obj) => { + const rtnLines = [] + if (obj.type === 'QPolygon') { + const points = obj.getCurrentPoints() + points.forEach((point, index) => { + const nextPoint = points[(index + 1) % points.length] // 마지막 점이면 첫 번째 점으로 연결 + const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], { + stroke: 'black', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, // fontSize는 필요에 따라 조정 + parent: obj, + }) + obj.visible = false + canvas.add(line) + rtnLines.push(line) + }) + + canvas.renderAll() + } + if (obj.type === 'QLine') { + const parent = obj.parent + canvas + ?.getObjects() + .filter((obj) => obj.parent === parent) + .forEach((obj) => { + rtnLines.push(obj) + canvas.remove(obj) + }) + + parent.visible = true + canvas.renderAll() + } + return rtnLines + } + return { mode, changeMode, @@ -808,5 +843,6 @@ export function useMode() { zoomIn, zoomOut, zoom, + togglePolygonLine, } } From 0c9ba3820961b5a3cfd19ac4c0745e0a75c3ba86 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 10 Jul 2024 10:29:32 +0900 Subject: [PATCH 085/113] =?UTF-8?q?=EC=A7=80=EB=B6=95=20=EA=B4=80=EB=A0=A8?= =?UTF-8?q?=20=EC=88=98=EC=B9=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/canvas-util.js | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index ca66ef48..ad75f204 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -178,7 +178,6 @@ export const rearrangeArray = (array, index) => { return fromIndexToEnd.concat(fromStartToIndex) } - export const findTopTwoIndexesByDistance = (objArr) => { if (objArr.length < 2) { return [] // 배열의 길이가 2보다 작으면 빈 배열 반환 @@ -204,4 +203,25 @@ export const findTopTwoIndexesByDistance = (objArr) => { } return [firstIndex, secondIndex] -} \ No newline at end of file +} + +/** + * 지붕의 누워있는 높이 + * @param base 밑변 + * @param degree 각도 ex(4촌의 경우 21.8) + */ +export const getRoofHeight = (base, degree) => { + return base / Math.cos((degree * Math.PI) / 180) +} + +/** + * 지붕 빗변의 길이 + * @param base 밑변 + */ +export const getRoofHypotenuse = (base) => { + return Math.sqrt(base * base * 2) +} + +export const getDegreeByChon = (chon) => { + return chon * 5.45 +} From 7218f7f9ea47dda57015a6f176b4df686c6d7e62 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 10 Jul 2024 11:25:35 +0900 Subject: [PATCH 086/113] =?UTF-8?q?polygon=20Qline=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?=EB=B0=8F=20currentPoints=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 22 +++++++++++++--- src/components/fabric/QLine.js | 3 +++ src/components/fabric/QPolygon.js | 44 ++++++++++++++++++++++++++----- src/hooks/useMode.js | 25 ++---------------- src/util/canvas-util.js | 39 +++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 33 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 141db8de..0376a4dc 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -45,6 +45,7 @@ export default function Roof2() { zoomIn, zoomOut, zoom, + togglePolygonLine, } = useMode() useEffect(() => { @@ -147,16 +148,18 @@ export default function Roof2() { strokeWidth: 1, selectable: true, fontSize: fontSize, + name: 'QPolygon1', }, canvas, // 필수로 넣어줘야 함 ) canvas?.add(polygon) - polygon.drawOuterLine(-50) + polygon.drawRoof(-50) addBackgroundInPolygon(polygon) - console.log(polygon.outerPolygon) + const lines = togglePolygonLine(polygon) + togglePolygonLine(lines[0]) } } @@ -192,11 +195,19 @@ export default function Roof2() { }) polygon.fillBackground(pattern) - - console.log(polygon) }) } + function PolygonToLine() { + const polygon = canvas?.getActiveObject() + + if (polygon.type !== 'QPolygon') { + return + } + + const lines = togglePolygonLine(polygon) + } + return ( <> {canvas && ( @@ -297,6 +308,9 @@ export default function Roof2() { +
diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 667fe213..c88430d2 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -11,6 +11,7 @@ export class QLine extends fabric.Group { y2 direction type = 'QLine' + parent constructor(points, option) { const [x1, y1, x2, y2] = points @@ -28,6 +29,8 @@ export class QLine extends fabric.Group { this.line = line this.fontSize = option.fontSize this.direction = option.direction + this.parent = option.parent + this.#init() this.#addControl() } diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index b20350b5..8c8c3b9e 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,15 +1,22 @@ import { fabric } from 'fabric' -import { distanceBetweenPoints } from '@/util/canvas-util' +import { + distanceBetweenPoints, + getDirection, + getDirectionByPoint, +} from '@/util/canvas-util' +import { QLine } from '@/components/fabric/QLine' export default class QPolygon extends fabric.Group { type = 'QPolygon' polygon points texts = [] + lines = [] canvas fontSize qCells = [] outerPolygon + name constructor(points, options, canvas) { if (!options.fontSize) { throw new Error('Font size is required.') @@ -19,15 +26,31 @@ export default class QPolygon extends fabric.Group { } const polygon = new fabric.Polygon(points, options) + super([polygon], {}) this.fontSize = options.fontSize this.points = points this.polygon = polygon - // this.canvas = canvas + this.name = options.name this.#init() this.#addEvent() + this.#initLines() + } + + #initLines() { + this.points.forEach((point, i) => { + const nextPoint = this.points[(i + 1) % this.points.length] + const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], { + stroke: 'black', + strokeWidth: 1, + fontSize: this.fontSize, + direction: getDirectionByPoint(point, nextPoint), + }) + + this.lines.push(line) + }) } #init() { @@ -241,19 +264,28 @@ export default class QPolygon extends fabric.Group { const scaleX = this.scaleX const scaleY = this.scaleY + const left = this.left + const top = this.top + + // 시작점 + const point = this.points[0] + + const movingX = left - point.x * scaleX + const movingY = top - point.y * scaleY + return this.points.map((point) => { return { - x: point.x * scaleX, - y: point.y * scaleY, + x: point.x * scaleX + movingX, + y: point.y * scaleY + movingY, } }) } /** - * 외곽선 그리기 + * 지붕 그리기 * @param offset */ - drawOuterLine(offset = -10) { + drawRoof(offset = -10) { const points = this.getCurrentPoints() const offsetPoints = [] for (let i = 0; i < points.length; i++) { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 5e816a72..f92d67e8 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -5,6 +5,7 @@ import { getStartIndex, rearrangeArray, findTopTwoIndexesByDistance, + getDirection, } from '@/util/canvas-util' import { useRecoilState } from 'recoil' import { fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' @@ -313,33 +314,11 @@ export function useMode() { }) } - /** - * 두 점 사이의 방향을 반환합니다. - */ - const getDirection = (a, b) => { - const vector = { - x: b.left - a.left, - y: b.top - a.top, - } - - if (Math.abs(vector.x) > Math.abs(vector.y)) { - // x축 방향으로 더 많이 이동 - return vector.x > 0 ? 'right' : 'left' - } else { - // y축 방향으로 더 많이 이동 - return vector.y > 0 ? 'bottom' : 'top' - } - } - /** * 두 점을 연결하는 선과 길이를 그립니다. * a : 시작점, b : 끝점 */ const drawLineWithLength = (a, b) => { - const vector = { - x: b.left - a.left, - y: b.top - a.top, - } const line = new QLine([a.left, a.top, b.left, b.top], { stroke: 'black', strokeWidth: 2, @@ -800,7 +779,7 @@ export function useMode() { offsetPoints.push(offsetPoint) } - + makePolygon(offsetPoints) } diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index ad75f204..d0e7b051 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -225,3 +225,42 @@ export const getRoofHypotenuse = (base) => { export const getDegreeByChon = (chon) => { return chon * 5.45 } + +/** + * 두 점 사이의 방향을 반환합니다. + * @param a {fabric.Object} + * @param b {fabric.Object} + * @returns {string} + */ +export const getDirection = (a, b) => { + const vector = { + x: b.left - a.left, + y: b.top - a.top, + } + + if (Math.abs(vector.x) > Math.abs(vector.y)) { + // x축 방향으로 더 많이 이동 + return vector.x > 0 ? 'right' : 'left' + } else { + // y축 방향으로 더 많이 이동 + return vector.y > 0 ? 'bottom' : 'top' + } +} + +/** + * 두 점 사이의 방향을 반환합니다. + */ +export const getDirectionByPoint = (a, b) => { + const vector = { + x: b.x - a.x, + y: b.y - a.y, + } + + if (Math.abs(vector.x) > Math.abs(vector.y)) { + // x축 방향으로 더 많이 이동 + return vector.x > 0 ? 'right' : 'left' + } else { + // y축 방향으로 더 많이 이동 + return vector.y > 0 ? 'bottom' : 'top' + } +} From c44fa88ed8ad6e6c64dc0f27d43f763aacccf3dc Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 10 Jul 2024 11:33:51 +0900 Subject: [PATCH 087/113] =?UTF-8?q?=EB=B3=80=EC=88=98=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 8c8c3b9e..378793f0 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -15,7 +15,7 @@ export default class QPolygon extends fabric.Group { canvas fontSize qCells = [] - outerPolygon + roof name constructor(points, options, canvas) { if (!options.fontSize) { @@ -333,7 +333,7 @@ export default class QPolygon extends fabric.Group { offsetPoints.push(offsetPoint) } - const outPolygon = new QPolygon( + const roof = new QPolygon( offsetPoints, { stroke: 'black', @@ -344,7 +344,7 @@ export default class QPolygon extends fabric.Group { this.canvas, ) - this.outerPolygon = outPolygon + this.roof = roof this.addWithUpdate(outPolygon) this.canvas.renderAll() From aebf4e0c4294e3655a15e8148ee5b0626a365d32 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 10 Jul 2024 17:00:16 +0900 Subject: [PATCH 088/113] =?UTF-8?q?=ED=85=9C=ED=94=8C=EB=A6=BF=20=EC=82=AC?= =?UTF-8?q?=EA=B0=81=ED=98=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 15 +- src/components/fabric/QLine.js | 22 ++- src/components/fabric/QPolygon.js | 244 +++++++++++++++++++++--------- src/hooks/useMode.js | 23 ++- src/store/canvasAtom.js | 14 +- src/util/canvas-util.js | 31 ++++ 6 files changed, 258 insertions(+), 91 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 0376a4dc..b4bff818 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -155,7 +155,6 @@ export default function Roof2() { canvas?.add(polygon) - polygon.drawRoof(-50) addBackgroundInPolygon(polygon) const lines = togglePolygonLine(polygon) @@ -176,11 +175,15 @@ export default function Roof2() { const makeQLine = () => { if (canvas) { - const line = new QLine([50, 50, 200, 50], { - stroke: 'black', - strokeWidth: 1, - fontSize: fontSize, - }) + const line = new QLine( + [50, 50, 200, 50], + { + stroke: 'black', + strokeWidth: 1, + fontSize: fontSize, + }, + 50, + ) canvas?.add(line) } diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index c88430d2..cbc64ed6 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -4,7 +4,7 @@ export class QLine extends fabric.Group { line text fontSize - length + length = 0 x1 y1 x2 @@ -13,12 +13,13 @@ export class QLine extends fabric.Group { type = 'QLine' parent - constructor(points, option) { + constructor(points, option, lengthTxt) { const [x1, y1, x2, y2] = points if (!option.fontSize) { throw new Error('Font size is required.') } + const line = new fabric.Line(points, { ...option, strokeWidth: 1 }) super([line], {}) @@ -31,6 +32,10 @@ export class QLine extends fabric.Group { this.direction = option.direction this.parent = option.parent + if (lengthTxt > 0) { + this.length = Number(lengthTxt) + } + this.#init() this.#addControl() } @@ -66,7 +71,16 @@ export class QLine extends fabric.Group { this.removeWithUpdate(this.text) this.text = null } - + if (this.length > 0) { + const text = new fabric.Textbox(this.length.toFixed(0).toString(), { + left: (this.x1 + this.x2) / 2, + top: (this.y1 + this.y2) / 2, + fontSize: this.fontSize, + }) + this.text = text + this.addWithUpdate(text) + return + } const scaleX = this.scaleX const scaleY = this.scaleY const x1 = this.left @@ -77,7 +91,7 @@ export class QLine extends fabric.Group { const dy = y2 - y1 this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) - const text = new fabric.Textbox(this.length.toString(), { + const text = new fabric.Textbox(this.length.toFixed(0).toString(), { left: (x1 + x2) / 2, top: (y1 + y2) / 2, fontSize: this.fontSize, diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 378793f0..c60670e1 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,8 +1,12 @@ import { fabric } from 'fabric' import { + calculateIntersection, distanceBetweenPoints, + getDegreeByChon, getDirection, getDirectionByPoint, + getRoofHeight, + getRoofHypotenuse, } from '@/util/canvas-util' import { QLine } from '@/components/fabric/QLine' @@ -15,7 +19,6 @@ export default class QPolygon extends fabric.Group { canvas fontSize qCells = [] - roof name constructor(points, options, canvas) { if (!options.fontSize) { @@ -43,8 +46,8 @@ export default class QPolygon extends fabric.Group { this.points.forEach((point, i) => { const nextPoint = this.points[(i + 1) % this.points.length] const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], { - stroke: 'black', - strokeWidth: 1, + stroke: this.stroke, + strokeWidth: this.strokeWidth, fontSize: this.fontSize, direction: getDirectionByPoint(point, nextPoint), }) @@ -88,7 +91,7 @@ export default class QPolygon extends fabric.Group { }) this.texts = [] } - const points = this.getCurrentPoints() + const points = this.points points.forEach((start, i) => { const end = points[(i + 1) % points.length] @@ -281,77 +284,170 @@ export default class QPolygon extends fabric.Group { }) } - /** - * 지붕 그리기 - * @param offset - */ - drawRoof(offset = -10) { - const points = this.getCurrentPoints() - const offsetPoints = [] - for (let i = 0; i < points.length; i++) { - const prev = points[(i - 1 + points.length) % points.length] - const current = points[i] - const next = points[(i + 1) % points.length] - - // 두 벡터 계산 (prev -> current, current -> next) - const vector1 = { x: current.x - prev.x, y: current.y - prev.y } - const vector2 = { x: next.x - current.x, y: next.y - current.y } - - // 벡터의 길이 계산 - const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) - const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) - - // 벡터를 단위 벡터로 정규화 - const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } - const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } - - // 법선 벡터 계산 (왼쪽 방향) - const normal1 = { x: -unitVector1.y, y: unitVector1.x } - const normal2 = { x: -unitVector2.y, y: unitVector2.x } - - // 법선 벡터 평균 계산 - const averageNormal = { - x: (normal1.x + normal2.x) / 2, - y: (normal1.y + normal2.y) / 2, - } - - // 평균 법선 벡터를 단위 벡터로 정규화 - const lengthNormal = Math.sqrt( - averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y, - ) - const unitNormal = { - x: averageNormal.x / lengthNormal, - y: averageNormal.y / lengthNormal, - } - - // 오프셋 적용 - const offsetPoint = { - x: current.x + unitNormal.x * offset, - y: current.y + unitNormal.y * offset, - } - - offsetPoints.push(offsetPoint) - } - - const roof = new QPolygon( - offsetPoints, - { - stroke: 'black', - strokeWidth: 1, - fill: 'transparent', - fontSize: this.fontSize, - }, - this.canvas, - ) - - this.roof = roof - - this.addWithUpdate(outPolygon) - this.canvas.renderAll() - } - fillBackground(pattern) { this.polygon.set({ fill: pattern }) - this.canvas.renderAll() + this.canvas.requestRenderAll() + } + + // 보조선 그리기 사각형에서만 + drawHelpLine(chon) { + let type + let smallestLength = Infinity + let maxLength = 0 + + this.lines.forEach((line) => { + if (line.length < smallestLength) { + smallestLength = line.length + } + if (line.length > maxLength) { + maxLength = line.length + } + }) + + const smallestLines = this.lines.filter( + (line) => line.length === smallestLength, + ) + + let needPlusLine + let needMinusLine + + const direction = smallestLines[0].direction + + if (direction === 'top' || direction === 'bottom') { + needPlusLine = + smallestLines[0].x1 < smallestLines[1].x1 + ? smallestLines[0] + : smallestLines[1] + needMinusLine = + needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0] + + type = 1 // 가로가 긴 사각형 + } + + if (direction === 'left' || direction === 'right') { + needPlusLine = + smallestLines[0].y1 < smallestLines[1].y1 + ? smallestLines[0] + : smallestLines[1] + needMinusLine = + needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0] + + type = 2 // 세로가 긴 사각형 + } + + let point1 + let point2 + + if (type === 1) { + point1 = { + x: needPlusLine.x1 + smallestLength / 2, + y: + needPlusLine.y1 > needPlusLine.y2 + ? needPlusLine.y1 - smallestLength / 2 + : needPlusLine.y2 - smallestLength / 2, + } + + point2 = { + x: needMinusLine.x1 - smallestLength / 2, + y: + needMinusLine.y1 > needMinusLine.y2 + ? needMinusLine.y1 - smallestLength / 2 + : needMinusLine.y2 - smallestLength / 2, + } + } else if (type === 2) { + point1 = { + x: + needPlusLine.x1 > needPlusLine.x2 + ? needPlusLine.x1 - smallestLength / 2 + : needPlusLine.x2 - smallestLength / 2, + y: needPlusLine.y1 + smallestLength / 2, + } + + point2 = { + x: + needMinusLine.x1 > needMinusLine.x2 + ? needMinusLine.x1 - smallestLength / 2 + : needMinusLine.x2 - smallestLength / 2, + y: needMinusLine.y1 - smallestLength / 2, + } + } + + // 빗변1 + const realLine1 = new QLine( + [needPlusLine.x1, needPlusLine.y1, point1.x, point1.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(smallestLength / 2), + ) + + // 빗변2 + const realLine2 = new QLine( + [needPlusLine.x2, needPlusLine.y2, point1.x, point1.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(smallestLength / 2), + ) + + // 빗변3 + const realLine3 = new QLine( + [needMinusLine.x1, needMinusLine.y1, point2.x, point2.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(smallestLength / 2), + ) + + // 빗변4 + const realLine4 = new QLine( + [needMinusLine.x2, needMinusLine.y2, point2.x, point2.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(smallestLength / 2), + ) + + let centerPoint1 + let centerPoint2 + + if (type === 1) { + centerPoint1 = { x: point1.x - smallestLength / 2, y: point1.y } + centerPoint2 = { x: point2.x + smallestLength / 2, y: point2.y } + } else if (type === 2) { + centerPoint1 = { x: point1.x, y: point1.y - smallestLength / 2 } + centerPoint2 = { x: point2.x, y: point2.y + smallestLength / 2 } + } + + // 옆으로 누워있는 지붕의 높이 + const realLine5 = new QLine( + [point1.x, point1.y, centerPoint1.x, centerPoint1.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + strokeDashArray: [5, 5], + }, + getRoofHeight(smallestLength / 2, getDegreeByChon(4)), + ) + + // 옆으로 누워있는 지붕의 높이 + const realLine6 = new QLine( + [point2.x, point2.y, centerPoint2.x, centerPoint2.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + strokeDashArray: [5, 5], + }, + getRoofHeight(smallestLength / 2, getDegreeByChon(4)), + ) + + // 용마루 + const ridge = new QLine([point1.x, point1.y, point2.x, point2.y], { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + }) + + this.addWithUpdate(realLine1) + this.addWithUpdate(realLine2) + this.addWithUpdate(realLine3) + this.addWithUpdate(realLine4) + this.addWithUpdate(realLine5) + this.addWithUpdate(realLine6) + this.addWithUpdate(ridge) } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index f92d67e8..28f7df70 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -7,8 +7,13 @@ import { findTopTwoIndexesByDistance, getDirection, } from '@/util/canvas-util' -import { useRecoilState } from 'recoil' -import { fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' +import { useRecoilState, useSetRecoilState } from 'recoil' +import { + fontSizeState, + roofState, + sortedPolygonArray, + wallState, +} from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' export const Mode = { @@ -30,6 +35,8 @@ export function useMode() { const [fontSize] = useRecoilState(fontSizeState) const [shape, setShape] = useState(0) const [sortedArray, setSortedArray] = useRecoilState(sortedPolygonArray) + const [roof, setRoof] = useRecoilState(roofState) + const [wall, setWall] = useRecoilState(wallState) const addEvent = (mode) => { switch (mode) { @@ -210,7 +217,8 @@ export function useMode() { // handleOuterlines() handleOuterlinesTest() //외곽선 그리기 테스트 - makePolygon() + const wall = makePolygon() + setWall(wall) } } @@ -398,11 +406,13 @@ export function useMode() { // 캔버스를 다시 그립니다. if (!otherLines) { - polygon.fillCell() + // polygon.fillCell() canvas.renderAll() polygon.setViewLengthText(false) setMode(Mode.DEFAULT) } + + return polygon } /** @@ -714,7 +724,6 @@ export function useMode() { } } - console.log(newOuterlines) makePolygon(newOuterlines) } @@ -780,7 +789,9 @@ export function useMode() { offsetPoints.push(offsetPoint) } - makePolygon(offsetPoints) + const roof = makePolygon(offsetPoints) + setRoof(roof) + roof.drawHelpLine() } const togglePolygonLine = (obj) => { diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index c4b5dd19..16f057b1 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -20,6 +20,18 @@ export const canvasSizeState = atom({ export const sortedPolygonArray = atom({ key: 'sortedArray', - default : [], + default: [], + dangerouslyAllowMutability: true, +}) + +export const roofState = atom({ + key: 'roof', + default: {}, + dangerouslyAllowMutability: true, +}) + +export const wallState = atom({ + key: 'wall', + default: {}, dangerouslyAllowMutability: true, }) diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index d0e7b051..769329bb 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -264,3 +264,34 @@ export const getDirectionByPoint = (a, b) => { return vector.y > 0 ? 'bottom' : 'top' } } + +export function calculateIntersection(line1, line2) { + const x1 = line1.x1, + y1 = line1.y1, + x2 = line1.x2, + y2 = line1.y2 + const x3 = line2.x1, + y3 = line2.y1, + x4 = line2.x2, + y4 = line2.y2 + + const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) + if (denom === 0) return null // 선분이 평행하거나 일치 + + const intersectX = + ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / denom + const intersectY = + ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / denom + + // 교차점이 두 선분의 x 좌표 범위 내에 있는지 확인 + if ( + intersectX < Math.min(x1, x2) || + intersectX > Math.max(x1, x2) || + intersectX < Math.min(x3, x4) || + intersectX > Math.max(x3, x4) + ) { + return null // 교차점이 선분 범위 밖에 있음 + } + + return { x: intersectX, y: intersectY } +} From 722f77bf6d2df0712bba9d6e5e2a2b96d2a1dd9f Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 10 Jul 2024 17:00:32 +0900 Subject: [PATCH 089/113] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index f92d67e8..f6ae5bfe 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -338,16 +338,7 @@ export function useMode() { if (!otherLines) { //외각선 기준 - const sortedIndex = getStartIndex(lines) - let tmpArraySorted = rearrangeArray(lines, sortedIndex) - - if (tmpArraySorted[0].direction === 'right') { - //시계방향 - tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 - } - - setSortedArray(tmpArraySorted) //recoil에 넣음 - const topIndex = findTopTwoIndexesByDistance(tmpArraySorted) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 + const topIndex = findTopTwoIndexesByDistance(sortedArray) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 //일단 배열 6개 짜리 기준의 선 번호 if (topIndex[0] === 4) { @@ -718,10 +709,12 @@ export function useMode() { makePolygon(newOuterlines) } - const handleOuterlinesTest = () => { + /** + *벽 지붕 외곽선 생성 + */ + const handleOuterlinesTest = (offset = 71) => { var offsetPoints = [] - let offset = 71 // == 100 - 29 - + const sortedIndex = getStartIndex(historyLines.current) let tmpArraySorted = rearrangeArray(historyLines.current, sortedIndex) @@ -730,6 +723,8 @@ export function useMode() { tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 } + setSortedArray(tmpArraySorted) //recoil에 넣음 + const points = tmpArraySorted.map((line) => ({ x: line.x1, y: line.y1, @@ -781,6 +776,25 @@ export function useMode() { } makePolygon(offsetPoints) + + drawDiagonalLines(tmpArraySorted) //대각선 그리기 + + } + + + const drawDiagonalLines = (sortedArray) => { + let splitCenter = 0 + if ( sortedArray[0].height > sortedArray[1].width ) { //세로형 네모 + splitCenter = sortedArray[0].length / 2 + + }else { //가로형 네모 + horiCenter = sortedArray[1].length / 2 + vertCenter = sortedArray[0].length / 2 + sortedArray.x1 + vertCenter // x값 + sortedArray.y1 + horiCenter // y값 + } + + } const togglePolygonLine = (obj) => { From 051ea8786113803df078f9441c9d4e2a34b4d904 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 10 Jul 2024 18:19:20 +0900 Subject: [PATCH 090/113] =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 22 +++++++++++----------- src/components/fabric/QPolygon.js | 22 ++++++++++++++++------ 2 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index cbc64ed6..9ccb1a5c 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -12,6 +12,7 @@ export class QLine extends fabric.Group { direction type = 'QLine' parent + #lengthTxt = 0 constructor(points, option, lengthTxt) { const [x1, y1, x2, y2] = points @@ -33,7 +34,7 @@ export class QLine extends fabric.Group { this.parent = option.parent if (lengthTxt > 0) { - this.length = Number(lengthTxt) + this.#lengthTxt = Number(lengthTxt) } this.#init() @@ -41,20 +42,16 @@ export class QLine extends fabric.Group { } #init() { - this.#addLengthText() + this.#addLengthText(true) } #addControl() { - this.on('added', () => { - this.#addLengthText() - }) - this.on('moving', () => { - this.#addLengthText() + this.#addLengthText(false) }) this.on('modified', (e) => { - this.#addLengthText() + this.#addLengthText(false) }) this.on('selected', () => { @@ -66,21 +63,24 @@ export class QLine extends fabric.Group { }) } - #addLengthText() { + #addLengthText(isFirst) { if (this.text) { this.removeWithUpdate(this.text) this.text = null } - if (this.length > 0) { - const text = new fabric.Textbox(this.length.toFixed(0).toString(), { + + if (isFirst && this.#lengthTxt > 0) { + const text = new fabric.Textbox(this.#lengthTxt.toFixed(0).toString(), { left: (this.x1 + this.x2) / 2, top: (this.y1 + this.y2) / 2, fontSize: this.fontSize, }) + this.length = this.#lengthTxt this.text = text this.addWithUpdate(text) return } + const scaleX = this.scaleX const scaleY = this.scaleY const x1 = this.left diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index c60670e1..bdca82aa 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,9 +1,7 @@ import { fabric } from 'fabric' import { - calculateIntersection, distanceBetweenPoints, getDegreeByChon, - getDirection, getDirectionByPoint, getRoofHeight, getRoofHypotenuse, @@ -81,6 +79,13 @@ export default class QPolygon extends fabric.Group { this.texts.forEach((text) => { text.set({ fontSize }) }) + + this.getObjects().forEach((obj) => { + if (obj.type === 'QLine') { + obj.setFontSize(fontSize) + } + }) + this.addWithUpdate() } @@ -304,9 +309,14 @@ export default class QPolygon extends fabric.Group { } }) - const smallestLines = this.lines.filter( - (line) => line.length === smallestLength, - ) + // QPolygon 객체의 모든 선들을 가져옵니다. + const lines = [...this.lines] + + // 이 선들을 길이에 따라 정렬합니다. + lines.sort((a, b) => a.length - b.length) + + // 정렬된 배열에서 가장 작은 두 선을 선택합니다. + const smallestLines = lines.slice(0, 2) let needPlusLine let needMinusLine @@ -448,6 +458,6 @@ export default class QPolygon extends fabric.Group { this.addWithUpdate(realLine4) this.addWithUpdate(realLine5) this.addWithUpdate(realLine6) - this.addWithUpdate(ridge) + this.canvas.add(ridge) } } From 68cb952b70a57831cf32b2a12a05462fa6b0907e Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 08:17:17 +0900 Subject: [PATCH 091/113] =?UTF-8?q?=EC=B4=8C=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80,=20type=EA=B2=80=EC=82=AC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 2 +- src/util/canvas-util.js | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index bdca82aa..43e39fd2 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -81,7 +81,7 @@ export default class QPolygon extends fabric.Group { }) this.getObjects().forEach((obj) => { - if (obj.type === 'QLine') { + if (obj.type[0] === 'Q') { obj.setFontSize(fontSize) } }) diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 769329bb..51634a00 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -222,8 +222,16 @@ export const getRoofHypotenuse = (base) => { return Math.sqrt(base * base * 2) } +/** + * 촌을 입력받아 각도를 반환 + * @param chon + * @returns {number} + */ export const getDegreeByChon = (chon) => { - return chon * 5.45 + // tan(theta) = height / base + const radians = Math.atan(chon / 10) + // 라디안을 도 단위로 변환 + return Number((radians * (180 / Math.PI)).toFixed(2)) } /** @@ -265,6 +273,12 @@ export const getDirectionByPoint = (a, b) => { } } +/** + * line을 두개를 이용해서 교차점을 찾는 함수 + * @param line1 + * @param line2 + * @returns {{x: number, y: number}|null} + */ export function calculateIntersection(line1, line2) { const x1 = line1.x1, y1 = line1.y1, From 446f5ba093aec90911e08d31617237e3e8a4a80c Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 10:57:23 +0900 Subject: [PATCH 092/113] =?UTF-8?q?qpolygon=20=EB=B0=A9=ED=96=A5=20line=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=ED=95=A8=EC=88=98=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 21 ++++---- src/components/fabric/QPolygon.js | 8 +-- src/hooks/useMode.js | 73 ++++++++++++++++++++++++- src/util/canvas-util.js | 90 +++++++++++++++++++++++++++++++ 4 files changed, 178 insertions(+), 14 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index b4bff818..5d1b997f 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -46,6 +46,7 @@ export default function Roof2() { zoomOut, zoom, togglePolygonLine, + handleOuterlinesTest2, } = useMode() useEffect(() => { @@ -135,12 +136,14 @@ export default function Roof2() { if (canvas) { const polygon = new QPolygon( [ - { x: 100, y: 100 }, - { x: 800, y: 100 }, - { x: 800, y: 800 }, - { x: 500, y: 800 }, - { x: 500, y: 400 }, - { x: 100, y: 400 }, + { x: 198.5, y: 735 }, + { x: 698.5, y: 735 }, + { x: 698.5, y: 585 }, + { x: 448.5, y: 585 }, + { x: 448.5, y: 435 }, + { x: 698.5, y: 435 }, + { x: 698.5, y: 235 }, + { x: 198.5, y: 235 }, ], { fill: 'transparent', @@ -155,10 +158,10 @@ export default function Roof2() { canvas?.add(polygon) - addBackgroundInPolygon(polygon) + handleOuterlinesTest2(polygon) - const lines = togglePolygonLine(polygon) - togglePolygonLine(lines[0]) + // const lines = togglePolygonLine(polygon) + // togglePolygonLine(lines[0]) } } diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 43e39fd2..d15c93dd 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -5,6 +5,7 @@ import { getDirectionByPoint, getRoofHeight, getRoofHypotenuse, + sortedPoints, } from '@/util/canvas-util' import { QLine } from '@/components/fabric/QLine' @@ -26,15 +27,14 @@ export default class QPolygon extends fabric.Group { throw new Error('Canvas is required.') } - const polygon = new fabric.Polygon(points, options) + const sortPoints = sortedPoints(points) + const polygon = new fabric.Polygon(sortPoints, options) super([polygon], {}) - this.fontSize = options.fontSize - this.points = points + this.points = sortPoints this.polygon = polygon this.name = options.name - this.#init() this.#addEvent() this.#initLines() diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 67e40b28..c8db2ac6 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -723,7 +723,7 @@ export function useMode() { */ const handleOuterlinesTest = (offset = 71) => { var offsetPoints = [] - + const sortedIndex = getStartIndex(historyLines.current) let tmpArraySorted = rearrangeArray(historyLines.current, sortedIndex) @@ -789,6 +789,76 @@ export function useMode() { roof.drawHelpLine() } + /** + *벽 지붕 외곽선 생성 polygon을 입력받아 만들기 + */ + const handleOuterlinesTest2 = (polygon, offset = 71) => { + const offsetPoints = [] + const sortedIndex = getStartIndex(polygon.lines) + let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex) + + if (tmpArraySorted[0].direction === 'right') { + //시계방향 + tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 + } + + setSortedArray(tmpArraySorted) //recoil에 넣음 + + const points = tmpArraySorted.map((line) => ({ + x: line.x1, + y: line.y1, + })) + + for (let i = 0; i < points.length; i++) { + const prev = points[(i - 1 + points.length) % points.length] + const current = points[i] + const next = points[(i + 1) % points.length] + + // 두 벡터 계산 (prev -> current, current -> next) + const vector1 = { x: current.x - prev.x, y: current.y - prev.y } + const vector2 = { x: next.x - current.x, y: next.y - current.y } + + // 벡터의 길이 계산 + const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) + const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) + + // 벡터를 단위 벡터로 정규화 + const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } + const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } + + // 법선 벡터 계산 (왼쪽 방향) + const normal1 = { x: -unitVector1.y, y: unitVector1.x } + const normal2 = { x: -unitVector2.y, y: unitVector2.x } + + // 법선 벡터 평균 계산 + const averageNormal = { + x: (normal1.x + normal2.x) / 2, + y: (normal1.y + normal2.y) / 2, + } + + // 평균 법선 벡터를 단위 벡터로 정규화 + const lengthNormal = Math.sqrt( + averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y, + ) + const unitNormal = { + x: averageNormal.x / lengthNormal, + y: averageNormal.y / lengthNormal, + } + + // 오프셋 적용 + const offsetPoint = { + x1: current.x + unitNormal.x * offset, + y1: current.y + unitNormal.y * offset, + } + + offsetPoints.push(offsetPoint) + } + + const roof = makePolygon(offsetPoints) + setRoof(roof) + // roof.drawHelpLine() + } + const togglePolygonLine = (obj) => { const rtnLines = [] if (obj.type === 'QPolygon') { @@ -834,5 +904,6 @@ export function useMode() { zoomOut, zoom, togglePolygonLine, + handleOuterlinesTest2, } } diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 51634a00..84563f34 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -155,6 +155,30 @@ export const getStartIndex = (lines) => { return smallestIndex } +/** + * points 배열에서 시작점을 찾는 함수 + * @param points + * @returns {number} + */ +export const getStartIndexPoint = (points) => { + let smallestIndex = 0 + let smallestX1 = points[0].x + let smallestY1 = points[0].y + + for (let i = 1; i < points.length; i++) { + if ( + points[i].x < smallestX1 || + (points[i].x === smallestX1 && points[i].y < smallestY1) + ) { + smallestIndex = i + smallestX1 = points[i].x + smallestY1 = points[i].y + } + } + + return smallestIndex +} + /** * 이 함수는 두 개의 매개변수를 받습니다: array와 index. * array는 재배열할 대상 배열입니다. @@ -309,3 +333,69 @@ export function calculateIntersection(line1, line2) { return { x: intersectX, y: intersectY } } + +/** + * points배열을 입력받아 반시계방향으로 정렬된 points를 반환합니다. + * @param points + */ +export const sortedPoints = (points) => { + const copyPoints = [...points] + //points를 x,y좌표를 기준으로 정렬합니다. + + copyPoints.sort((a, b) => { + if (a.x === b.x) { + return a.y - b.y + } + return a.x - b.x + }) + + // 이때 copyPoints를 순회하며 최초엔 x값을 비교하여 같은 점을 찾는다. 이때 이 점이 2번째 점이 된다. + // 그 다음점은 2번째 점과 y값이 같은 점이 된다. + // 또 그다음 점은 3번째 점과 x값이 같은 점이 된다. + // 이를 반복하여 copyPoints를 재배열한다. + const resultPoints = [copyPoints[0]] + let index = 1 + let currentPoint = { ...copyPoints[0] } + copyPoints.splice(0, 1) + + while (index < points.length) { + if (index === points.length - 1) { + resultPoints.push(copyPoints[0]) + index++ + break + } else if (index % 2 === 0) { + // 짝수번째는 y값이 같은 점을 찾는다. + 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) + index++ + break + } + } else { + // 홀수번째는 x값이 같은 점을 찾는다. + 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, + ) + + resultPoints.push(max) + currentPoint = max + copyPoints.splice(copyPoints.indexOf(max), 1) + index++ + break + } + } + } + + return resultPoints +} From b04e7128a7f6d2c4affb873364b5ee0f3d910324 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 11:17:26 +0900 Subject: [PATCH 093/113] =?UTF-8?q?=EC=A0=90=206=EA=B0=9C=EC=9D=BC?= =?UTF-8?q?=EB=95=8C=20shape=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 49 +++++++++++++++++++++++++++++++ src/hooks/useMode.js | 2 ++ 2 files changed, 51 insertions(+) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index d15c93dd..3a7d2020 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,6 +1,7 @@ import { fabric } from 'fabric' import { distanceBetweenPoints, + findTopTwoIndexesByDistance, getDegreeByChon, getDirectionByPoint, getRoofHeight, @@ -19,6 +20,7 @@ export default class QPolygon extends fabric.Group { fontSize qCells = [] name + shape = 0 // 점 6개일때의 shape 모양 constructor(points, options, canvas) { if (!options.fontSize) { throw new Error('Font size is required.') @@ -38,6 +40,7 @@ export default class QPolygon extends fabric.Group { this.#init() this.#addEvent() this.#initLines() + this.setShape() } #initLines() { @@ -460,4 +463,50 @@ export default class QPolygon extends fabric.Group { this.addWithUpdate(realLine6) this.canvas.add(ridge) } + + /** + * 현재 점 6개만 가능 + */ + setShape() { + let shape = 0 + if (this.lines.length !== 6) { + throw new Error('Only 6 points are allowed.') + } + //외각선 기준 + const topIndex = findTopTwoIndexesByDistance(this.lines) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 + + //일단 배열 6개 짜리 기준의 선 번호 + if (topIndex[0] === 4) { + if (topIndex[1] === 5) { + //1번 + shape = 1 + } + } else if (topIndex[0] === 1) { + //4번 + if (topIndex[1] === 2) { + shape = 4 + } + } else if (topIndex[0] === 0) { + if (topIndex[1] === 1) { + //2번 + shape = 2 + } else if (topIndex[1] === 5) { + //3번 + shape = 3 + } + } + + this.shape = shape + } + + /** + * 현재 점 6개만 가능 + * @returns {number} + */ + getShape() { + if (this.lines.length !== 6) { + throw new Error('Only 6 points are allowed.') + } + return this.shape + } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index c8db2ac6..6d89a0df 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -392,6 +392,8 @@ export function useMode() { canvas, ) + console.log(polygon.getShape()) + // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) From 3cf2813d3d10762194f666f52c31aff2e9bddee2 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 11:32:45 +0900 Subject: [PATCH 094/113] =?UTF-8?q?6=EA=B0=9C=EA=B0=80=20=EC=95=84?= =?UTF-8?q?=EB=8B=90=EB=95=8C=20=EC=95=88=EB=90=98=EB=8A=94=20=ED=98=84?= =?UTF-8?q?=EC=83=81=20=EC=9A=B0=EC=84=A0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 5 +---- src/hooks/useMode.js | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 3a7d2020..ccffbc92 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -470,7 +470,7 @@ export default class QPolygon extends fabric.Group { setShape() { let shape = 0 if (this.lines.length !== 6) { - throw new Error('Only 6 points are allowed.') + return } //외각선 기준 const topIndex = findTopTwoIndexesByDistance(this.lines) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 @@ -504,9 +504,6 @@ export default class QPolygon extends fabric.Group { * @returns {number} */ getShape() { - if (this.lines.length !== 6) { - throw new Error('Only 6 points are allowed.') - } return this.shape } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 6d89a0df..c8db2ac6 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -392,8 +392,6 @@ export function useMode() { canvas, ) - console.log(polygon.getShape()) - // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) From 745c07f5ecea9e5ac8f54f5af13c8773226a90df Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 12:01:40 +0900 Subject: [PATCH 095/113] =?UTF-8?q?=EC=A0=95=EC=82=AC=EA=B0=81=ED=98=95=20?= =?UTF-8?q?=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 111 +++++++++++++++++------------- 1 file changed, 64 insertions(+), 47 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index ccffbc92..72b3e911 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -298,7 +298,56 @@ export default class QPolygon extends fabric.Group { } // 보조선 그리기 사각형에서만 - drawHelpLine(chon) { + drawHelpLine(chon = 4) { + if (this.lines.length === 4) { + this.#drawHelpLineInRect(chon) + } + } + + /** + * 현재 점 6개만 가능 + */ + setShape() { + let shape = 0 + if (this.lines.length !== 6) { + return + } + //외각선 기준 + const topIndex = findTopTwoIndexesByDistance(this.lines) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 + + //일단 배열 6개 짜리 기준의 선 번호 + if (topIndex[0] === 4) { + if (topIndex[1] === 5) { + //1번 + shape = 1 + } + } else if (topIndex[0] === 1) { + //4번 + if (topIndex[1] === 2) { + shape = 4 + } + } else if (topIndex[0] === 0) { + if (topIndex[1] === 1) { + //2번 + shape = 2 + } else if (topIndex[1] === 5) { + //3번 + shape = 3 + } + } + + this.shape = shape + } + + /** + * 현재 점 6개만 가능 + * @returns {number} + */ + getShape() { + return this.shape + } + + #drawHelpLineInRect(chon) { let type let smallestLength = Infinity let maxLength = 0 @@ -319,7 +368,15 @@ export default class QPolygon extends fabric.Group { lines.sort((a, b) => a.length - b.length) // 정렬된 배열에서 가장 작은 두 선을 선택합니다. - const smallestLines = lines.slice(0, 2) + let smallestLines + + if (smallestLength === maxLength) { + // 정사각형인 경우 0, 2번째 라인이 가장 짧은 라인 + + smallestLines = [lines[0], lines[2]] + } else { + smallestLines = lines.slice(0, 2) + } let needPlusLine let needMinusLine @@ -433,7 +490,7 @@ export default class QPolygon extends fabric.Group { strokeWidth: 1, strokeDashArray: [5, 5], }, - getRoofHeight(smallestLength / 2, getDegreeByChon(4)), + getRoofHeight(smallestLength / 2, getDegreeByChon(chon)), ) // 옆으로 누워있는 지붕의 높이 @@ -445,7 +502,7 @@ export default class QPolygon extends fabric.Group { strokeWidth: 1, strokeDashArray: [5, 5], }, - getRoofHeight(smallestLength / 2, getDegreeByChon(4)), + getRoofHeight(smallestLength / 2, getDegreeByChon(chon)), ) // 용마루 @@ -461,49 +518,9 @@ export default class QPolygon extends fabric.Group { this.addWithUpdate(realLine4) this.addWithUpdate(realLine5) this.addWithUpdate(realLine6) - this.canvas.add(ridge) - } - - /** - * 현재 점 6개만 가능 - */ - setShape() { - let shape = 0 - if (this.lines.length !== 6) { - return + if (smallestLength !== maxLength) { + // 정사각형이 아닌경우에만 용마루를 추가한다. + this.canvas.add(ridge) } - //외각선 기준 - const topIndex = findTopTwoIndexesByDistance(this.lines) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 - - //일단 배열 6개 짜리 기준의 선 번호 - if (topIndex[0] === 4) { - if (topIndex[1] === 5) { - //1번 - shape = 1 - } - } else if (topIndex[0] === 1) { - //4번 - if (topIndex[1] === 2) { - shape = 4 - } - } else if (topIndex[0] === 0) { - if (topIndex[1] === 1) { - //2번 - shape = 2 - } else if (topIndex[1] === 5) { - //3번 - shape = 3 - } - } - - this.shape = shape - } - - /** - * 현재 점 6개만 가능 - * @returns {number} - */ - getShape() { - return this.shape } } From 1805383ce09158732491303b85c3865bddb6efd1 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 12:04:00 +0900 Subject: [PATCH 096/113] =?UTF-8?q?=EB=B3=B4=EC=A1=B0=EC=84=A0=20todo=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 72b3e911..dd4eda10 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -301,6 +301,10 @@ export default class QPolygon extends fabric.Group { drawHelpLine(chon = 4) { if (this.lines.length === 4) { this.#drawHelpLineInRect(chon) + } else if (this.lines.length === 6) { + this.#drawHelpLineInHexagon(chon) + } else if (this.lines.length === 8) { + this.#drawHelpLineInOctagon(chon) } } @@ -523,4 +527,8 @@ export default class QPolygon extends fabric.Group { this.canvas.add(ridge) } } + + #drawHelpLineInHexagon(chon) {} + + #drawHelpLineInOctagon(chon) {} } From f5fc2d29bf50ccc020b1947b361cdce012cbfb7d Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 12:04:41 +0900 Subject: [PATCH 097/113] =?UTF-8?q?=EC=A3=BC=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index dd4eda10..7892b5e6 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -302,8 +302,10 @@ export default class QPolygon extends fabric.Group { if (this.lines.length === 4) { this.#drawHelpLineInRect(chon) } else if (this.lines.length === 6) { + // TODO : 6각형 this.#drawHelpLineInHexagon(chon) } else if (this.lines.length === 8) { + // TODO : 8각형 this.#drawHelpLineInOctagon(chon) } } From 17424457a9e047d1d4a8daf03d703ecb0fe43b9f Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 15:33:49 +0900 Subject: [PATCH 098/113] =?UTF-8?q?6=EA=B0=81=ED=98=95=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 22 ++- src/components/fabric/QPolygon.js | 239 +++++++++++++++++++++++++++++- src/hooks/useMode.js | 2 +- 3 files changed, 252 insertions(+), 11 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 5d1b997f..95414216 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -136,14 +136,20 @@ export default function Roof2() { if (canvas) { const polygon = new QPolygon( [ - { x: 198.5, y: 735 }, - { x: 698.5, y: 735 }, - { x: 698.5, y: 585 }, - { x: 448.5, y: 585 }, - { x: 448.5, y: 435 }, - { x: 698.5, y: 435 }, - { x: 698.5, y: 235 }, - { x: 198.5, y: 235 }, + // { x: 198.5, y: 735 }, + // { x: 698.5, y: 735 }, + // { x: 698.5, y: 585 }, + // { x: 448.5, y: 585 }, + // { x: 448.5, y: 435 }, + // { x: 698.5, y: 435 }, + // { x: 698.5, y: 235 }, + // { x: 198.5, y: 235 }, + { x: 100, y: 100 }, + { x: 800, y: 100 }, + { x: 800, y: 800 }, + { x: 500, y: 800 }, + { x: 500, y: 400 }, + { x: 100, y: 400 }, ], { fill: 'transparent', diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 7892b5e6..b9a20111 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -33,6 +33,7 @@ export default class QPolygon extends fabric.Group { const polygon = new fabric.Polygon(sortPoints, options) super([polygon], {}) + this.fontSize = options.fontSize this.points = sortPoints this.polygon = polygon @@ -354,7 +355,7 @@ export default class QPolygon extends fabric.Group { } #drawHelpLineInRect(chon) { - let type + let type = 1 let smallestLength = Infinity let maxLength = 0 @@ -530,7 +531,241 @@ export default class QPolygon extends fabric.Group { } } - #drawHelpLineInHexagon(chon) {} + #drawHelpLineInHexagon(chon) { + let type = this.shape + + // 1 = 0, 3 + // 2 = 2, 5 + // 3 = 1, 4 + // 4 = 0, 3 + + // 라인 기준점 1,2 + let lines, lines2 + // 용마루 시작점 2개 + let vPoint1, vPoint2 + // 용마루 시작점과 만나는 지붕의 중앙 + let centerPoint1, centerPoint2 + // 용마루 끝점을 위해 필요한 점 2개 + let vPoint3, vPoint4 + + if (type === 1) { + lines = [this.lines[0], this.lines[3]] + lines2 = [this.lines[1], this.lines[4]] + vPoint1 = { + x: lines[0].x1 + lines[0].length / 2, + y: lines[0].y1 + lines[0].length / 2, + } + vPoint2 = { + x: lines[1].x1 + lines[1].length / 2, + y: lines[1].y1 - lines[1].length / 2, + } + centerPoint1 = { + x: (lines[0].x1 + lines[0].x2) / 2, + y: (lines[0].y1 + lines[0].y2) / 2, + } + centerPoint2 = { + x: (lines[1].x1 + lines[1].x2) / 2, + y: (lines[1].y1 + lines[1].y2) / 2, + } + vPoint3 = { + x: lines2[0].x2 + lines[0].length / 2, + y: lines2[0].y2 - lines[0].length / 2, + } + vPoint4 = { + x: lines2[1].x2 - lines[1].length / 2, + y: lines2[1].y2 + lines[1].length / 2, + } + } else if (type === 2) { + lines = [this.lines[2], this.lines[5]] + lines2 = [this.lines[0], this.lines[3]] + vPoint1 = { + x: lines[0].x1 - lines[0].length / 2, + y: lines[0].y1 - lines[0].length / 2, + } + vPoint2 = { + x: lines[1].x1 - lines[1].length / 2, + y: lines[1].y1 + lines[1].length / 2, + } + centerPoint1 = { + x: (lines[0].x1 + lines[0].x2) / 2, + y: (lines[0].y1 + lines[0].y2) / 2, + } + centerPoint2 = { + x: (lines[1].x1 + lines[1].x2) / 2, + y: (lines[1].y1 + lines[1].y2) / 2, + } + vPoint3 = { + x: lines2[0].x2 + lines[0].length / 2, + y: lines2[0].y2 - lines[0].length / 2, + } + vPoint4 = { + x: lines2[1].x2 - lines[1].length / 2, + y: lines2[1].y2 + lines[1].length / 2, + } + } else if (type === 3) { + lines = [this.lines[1], this.lines[4]] + lines2 = [this.lines[2], this.lines[5]] + vPoint1 = { + x: lines[0].x1 + lines[0].length / 2, + y: lines[0].y1 - lines[0].length / 2, + } + vPoint2 = { + x: lines[1].x1 - lines[1].length / 2, + y: lines[1].y1 - lines[1].length / 2, + } + centerPoint1 = { + x: (lines[0].x1 + lines[0].x2) / 2, + y: (lines[0].y1 + lines[0].y2) / 2, + } + centerPoint2 = { + x: (lines[1].x1 + lines[1].x2) / 2, + y: (lines[1].y1 + lines[1].y2) / 2, + } + vPoint3 = { + x: lines2[0].x2 - lines[0].length / 2, + y: lines2[0].y2 - lines[0].length / 2, + } + vPoint4 = { + x: lines2[1].x2 + lines[1].length / 2, + y: lines2[1].y2 + lines[1].length / 2, + } + } else if (type === 4) { + lines = [this.lines[0], this.lines[3]] + lines2 = [this.lines[1], this.lines[4]] + vPoint1 = { + x: lines[0].x1 + lines[0].length / 2, + y: lines[0].y1 + lines[0].length / 2, + } + vPoint2 = { + x: lines[1].x1 - lines[1].length / 2, + y: lines[1].y1 + lines[1].length / 2, + } + centerPoint1 = { + x: (lines[0].x1 + lines[0].x2) / 2, + y: (lines[0].y1 + lines[0].y2) / 2, + } + centerPoint2 = { + x: (lines[1].x1 + lines[1].x2) / 2, + y: (lines[1].y1 + lines[1].y2) / 2, + } + vPoint3 = { + x: lines2[0].x2 - lines[0].length / 2, + y: lines2[0].y2 - lines[0].length / 2, + } + vPoint4 = { + x: lines2[1].x2 + lines[1].length / 2, + y: lines2[1].y2 + lines[1].length / 2, + } + } + + const realLine1 = new QLine( + [lines[0].x1, lines[0].y1, vPoint1.x, vPoint1.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(lines[0].length / 2), + ) + + const realLine2 = new QLine( + [lines[0].x2, lines[0].y2, vPoint1.x, vPoint1.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(lines[1].length / 2), + ) + + const realLine3 = new QLine( + [lines[1].x1, lines[1].y1, vPoint2.x, vPoint2.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(lines[1].length / 2), + ) + + const realLine4 = new QLine( + [lines[1].x2, lines[1].y2, vPoint2.x, vPoint2.y], + { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, + getRoofHypotenuse(lines[1].length / 2), + ) + + // 옆으로 누워있는 지붕의 높이 + const realLine5 = new QLine( + [vPoint1.x, vPoint1.y, centerPoint1.x, centerPoint1.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + strokeDashArray: [5, 5], + }, + getRoofHeight(lines[0].length / 2, getDegreeByChon(chon)), + ) + + // 옆으로 누워있는 지붕의 높이 + const realLine6 = new QLine( + [vPoint2.x, vPoint2.y, centerPoint2.x, centerPoint2.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + strokeDashArray: [5, 5], + }, + getRoofHeight(lines[1].length / 2, getDegreeByChon(chon)), + ) + + // 용마루 보조선 + const ridgeHelpLine1 = new QLine( + [lines2[0].x2, lines2[0].y2, vPoint3.x, vPoint3.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + }, + getRoofHypotenuse(lines[0].length / 2), + ) + + // 용마루 보조선 + const ridgeHelpLine2 = new QLine( + [lines2[1].x2, lines2[1].y2, vPoint4.x, vPoint4.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + }, + getRoofHypotenuse(lines[1].length / 2), + ) + + // 용마루 + const ridge1 = new QLine([vPoint1.x, vPoint1.y, vPoint3.x, vPoint3.y], { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + }) + + // 용마루 + const ridge2 = new QLine([vPoint2.x, vPoint2.y, vPoint4.x, vPoint4.y], { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + }) + + console.log(vPoint3, vPoint4) + const ridgeEndLine = new QLine( + [vPoint3.x, vPoint3.y, vPoint4.x, vPoint4.y], + { + fontSize: this.fontSize, + stroke: 'black', + strokeWidth: 1, + }, + ) + + this.addWithUpdate(realLine1) + this.addWithUpdate(realLine2) + this.addWithUpdate(realLine3) + this.addWithUpdate(realLine4) + this.addWithUpdate(realLine5) + this.addWithUpdate(realLine6) + this.addWithUpdate(ridgeHelpLine1) + this.addWithUpdate(ridgeHelpLine2) + this.addWithUpdate(ridge1) + this.addWithUpdate(ridge2) + this.addWithUpdate(ridgeEndLine) + + this.canvas.renderAll() + } #drawHelpLineInOctagon(chon) {} } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index c8db2ac6..ae925db0 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -856,7 +856,7 @@ export function useMode() { const roof = makePolygon(offsetPoints) setRoof(roof) - // roof.drawHelpLine() + roof.drawHelpLine() } const togglePolygonLine = (obj) => { From d529e9414346757821f159dc2780b41be8046b49 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 17:00:29 +0900 Subject: [PATCH 099/113] =?UTF-8?q?6=EA=B0=81=ED=98=95=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 51 +++++++++++++++------- src/components/fabric/QPolygon.js | 72 +++++++++++++------------------ 2 files changed, 64 insertions(+), 59 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 95414216..a4b80b6f 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -133,24 +133,43 @@ export default function Roof2() { }, [verticalSize, horizontalSize]) const makeQPolygon = () => { + const type1 = [ + { x: 100, y: 100 }, + { x: 800, y: 100 }, + { x: 800, 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: 100, y: 50 }, + { x: 100, y: 650 }, + { x: 450, y: 650 }, + { x: 450, y: 400 }, + { x: 700, y: 400 }, + { x: 700, y: 50 }, + ] + + const type4 = [ + { x: 153.96209743461895, y: 446.46989831140326 }, + { x: 153.96209743461895, y: 796.879061239893 }, + { x: 754.3712603631087, y: 796.879061239893 }, + { x: 754.3712603631087, y: 196.46989831140326 }, + { x: 403.962097434619, y: 196.46989831140326 }, + { x: 403.962097434619, y: 446.46989831140326 }, + ] if (canvas) { const polygon = new QPolygon( - [ - // { x: 198.5, y: 735 }, - // { x: 698.5, y: 735 }, - // { x: 698.5, y: 585 }, - // { x: 448.5, y: 585 }, - // { x: 448.5, y: 435 }, - // { x: 698.5, y: 435 }, - // { x: 698.5, y: 235 }, - // { x: 198.5, y: 235 }, - { x: 100, y: 100 }, - { x: 800, y: 100 }, - { x: 800, y: 800 }, - { x: 500, y: 800 }, - { x: 500, y: 400 }, - { x: 100, y: 400 }, - ], + type4, { fill: 'transparent', stroke: 'black', diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index b9a20111..7310456e 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -30,6 +30,7 @@ export default class QPolygon extends fabric.Group { } const sortPoints = sortedPoints(points) + console.log(sortPoints) const polygon = new fabric.Polygon(sortPoints, options) super([polygon], {}) @@ -545,9 +546,10 @@ export default class QPolygon extends fabric.Group { let vPoint1, vPoint2 // 용마루 시작점과 만나는 지붕의 중앙 let centerPoint1, centerPoint2 - // 용마루 끝점을 위해 필요한 점 2개 - let vPoint3, vPoint4 + // 용마루 길이 + let ridgeLength = 0 + let ridgePoint1, ridgePoint2 if (type === 1) { lines = [this.lines[0], this.lines[3]] lines2 = [this.lines[1], this.lines[4]] @@ -567,14 +569,10 @@ export default class QPolygon extends fabric.Group { x: (lines[1].x1 + lines[1].x2) / 2, y: (lines[1].y1 + lines[1].y2) / 2, } - vPoint3 = { - x: lines2[0].x2 + lines[0].length / 2, - y: lines2[0].y2 - lines[0].length / 2, - } - vPoint4 = { - x: lines2[1].x2 - lines[1].length / 2, - y: lines2[1].y2 + lines[1].length / 2, - } + + ridgeLength = Math.min(this.lines[1].length, this.lines[2].length) + ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x + ridgeLength, vPoint1.y] + ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y - ridgeLength] } else if (type === 2) { lines = [this.lines[2], this.lines[5]] lines2 = [this.lines[0], this.lines[3]] @@ -594,14 +592,10 @@ export default class QPolygon extends fabric.Group { x: (lines[1].x1 + lines[1].x2) / 2, y: (lines[1].y1 + lines[1].y2) / 2, } - vPoint3 = { - x: lines2[0].x2 + lines[0].length / 2, - y: lines2[0].y2 - lines[0].length / 2, - } - vPoint4 = { - x: lines2[1].x2 - lines[1].length / 2, - y: lines2[1].y2 + lines[1].length / 2, - } + + ridgeLength = Math.min(this.lines[3].length, this.lines[4].length) + ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x - ridgeLength, vPoint1.y] + ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y + ridgeLength] } else if (type === 3) { lines = [this.lines[1], this.lines[4]] lines2 = [this.lines[2], this.lines[5]] @@ -621,14 +615,10 @@ export default class QPolygon extends fabric.Group { x: (lines[1].x1 + lines[1].x2) / 2, y: (lines[1].y1 + lines[1].y2) / 2, } - vPoint3 = { - x: lines2[0].x2 - lines[0].length / 2, - y: lines2[0].y2 - lines[0].length / 2, - } - vPoint4 = { - x: lines2[1].x2 + lines[1].length / 2, - y: lines2[1].y2 + lines[1].length / 2, - } + + ridgeLength = Math.min(this.lines[0].length, this.lines[3].length) + ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x, vPoint1.y - ridgeLength] + ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x - ridgeLength, vPoint2.y] } else if (type === 4) { lines = [this.lines[0], this.lines[3]] lines2 = [this.lines[1], this.lines[4]] @@ -648,14 +638,10 @@ export default class QPolygon extends fabric.Group { x: (lines[1].x1 + lines[1].x2) / 2, y: (lines[1].y1 + lines[1].y2) / 2, } - vPoint3 = { - x: lines2[0].x2 - lines[0].length / 2, - y: lines2[0].y2 - lines[0].length / 2, - } - vPoint4 = { - x: lines2[1].x2 + lines[1].length / 2, - y: lines2[1].y2 + lines[1].length / 2, - } + + ridgeLength = Math.min(this.lines[2].length, this.lines[5].length) + ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x + ridgeLength, vPoint1.y] + ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y + ridgeLength] } const realLine1 = new QLine( @@ -667,7 +653,7 @@ export default class QPolygon extends fabric.Group { const realLine2 = new QLine( [lines[0].x2, lines[0].y2, vPoint1.x, vPoint1.y], { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, - getRoofHypotenuse(lines[1].length / 2), + getRoofHypotenuse(lines[0].length / 2), ) const realLine3 = new QLine( @@ -682,7 +668,7 @@ export default class QPolygon extends fabric.Group { getRoofHypotenuse(lines[1].length / 2), ) - // 옆으로 누워있는 지붕의 높이 + // 옆으로 누워있는 지붕의 높이 점선 const realLine5 = new QLine( [vPoint1.x, vPoint1.y, centerPoint1.x, centerPoint1.y], { @@ -694,7 +680,7 @@ export default class QPolygon extends fabric.Group { getRoofHeight(lines[0].length / 2, getDegreeByChon(chon)), ) - // 옆으로 누워있는 지붕의 높이 + // 옆으로 누워있는 지붕의 높이 점선 const realLine6 = new QLine( [vPoint2.x, vPoint2.y, centerPoint2.x, centerPoint2.y], { @@ -708,7 +694,7 @@ export default class QPolygon extends fabric.Group { // 용마루 보조선 const ridgeHelpLine1 = new QLine( - [lines2[0].x2, lines2[0].y2, vPoint3.x, vPoint3.y], + [lines2[1].x2, lines2[1].y2, ridgePoint1[2], ridgePoint1[3]], { fontSize: this.fontSize, stroke: 'black', @@ -719,7 +705,7 @@ export default class QPolygon extends fabric.Group { // 용마루 보조선 const ridgeHelpLine2 = new QLine( - [lines2[1].x2, lines2[1].y2, vPoint4.x, vPoint4.y], + [lines2[0].x2, lines2[0].y2, ridgePoint2[2], ridgePoint2[3]], { fontSize: this.fontSize, stroke: 'black', @@ -729,22 +715,21 @@ export default class QPolygon extends fabric.Group { ) // 용마루 - const ridge1 = new QLine([vPoint1.x, vPoint1.y, vPoint3.x, vPoint3.y], { + const ridge1 = new QLine(ridgePoint1, { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1, }) // 용마루 - const ridge2 = new QLine([vPoint2.x, vPoint2.y, vPoint4.x, vPoint4.y], { + const ridge2 = new QLine(ridgePoint2, { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1, }) - console.log(vPoint3, vPoint4) const ridgeEndLine = new QLine( - [vPoint3.x, vPoint3.y, vPoint4.x, vPoint4.y], + [ridgePoint1[2], ridgePoint1[3], ridgePoint2[2], ridgePoint2[3]], { fontSize: this.fontSize, stroke: 'black', @@ -765,6 +750,7 @@ export default class QPolygon extends fabric.Group { this.addWithUpdate(ridgeEndLine) this.canvas.renderAll() + console.log(JSON.stringify(this.points)) } #drawHelpLineInOctagon(chon) {} From 5d1b2ef5907d8f9f5d1486cc8a46a3c09bc4f17a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 17:05:29 +0900 Subject: [PATCH 100/113] =?UTF-8?q?=EB=81=BC=EC=9B=8C=EB=A7=9E=EC=B6=94?= =?UTF-8?q?=EA=B8=B0=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 2 +- src/components/fabric/QPolygon.js | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index a4b80b6f..270e4fda 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -169,7 +169,7 @@ export default function Roof2() { ] if (canvas) { const polygon = new QPolygon( - type4, + type2, { fill: 'transparent', stroke: 'black', diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 7310456e..2f1842ed 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -735,6 +735,7 @@ export default class QPolygon extends fabric.Group { stroke: 'black', strokeWidth: 1, }, + Math.abs(realLine1.length - realLine3.length), ) this.addWithUpdate(realLine1) From f40d8a7afb29eb3bbb0e2ccec88668a42f37c043 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 17:18:18 +0900 Subject: [PATCH 101/113] =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 12 ++++++------ src/components/fabric/QPolygon.js | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 270e4fda..9e8f55ff 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -151,12 +151,12 @@ export default function Roof2() { ] const type3 = [ - { x: 100, y: 50 }, - { x: 100, y: 650 }, + { x: 200, y: 150 }, + { x: 200, y: 650 }, { x: 450, y: 650 }, - { x: 450, y: 400 }, - { x: 700, y: 400 }, - { x: 700, y: 50 }, + { x: 450, y: 500 }, + { x: 650, y: 500 }, + { x: 650, y: 150 }, ] const type4 = [ @@ -169,7 +169,7 @@ export default function Roof2() { ] if (canvas) { const polygon = new QPolygon( - type2, + type3, { fill: 'transparent', stroke: 'black', diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 2f1842ed..7fbe9d4a 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -616,7 +616,7 @@ export default class QPolygon extends fabric.Group { y: (lines[1].y1 + lines[1].y2) / 2, } - ridgeLength = Math.min(this.lines[0].length, this.lines[3].length) + ridgeLength = Math.min(this.lines[2].length, this.lines[3].length) ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x, vPoint1.y - ridgeLength] ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x - ridgeLength, vPoint2.y] } else if (type === 4) { From 88b73eb91ec11a78ed1c4fb053c892509c262866 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 11 Jul 2024 17:42:45 +0900 Subject: [PATCH 102/113] =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 18 +++++++++--------- src/components/fabric/QPolygon.js | 12 ++++++------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 9e8f55ff..3dbfc5c7 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -135,8 +135,8 @@ export default function Roof2() { const makeQPolygon = () => { const type1 = [ { x: 100, y: 100 }, - { x: 800, y: 100 }, - { x: 800, y: 800 }, + { x: 850, y: 100 }, + { x: 850, y: 800 }, { x: 500, y: 800 }, { x: 500, y: 400 }, { x: 100, y: 400 }, @@ -160,16 +160,16 @@ export default function Roof2() { ] const type4 = [ - { x: 153.96209743461895, y: 446.46989831140326 }, - { x: 153.96209743461895, y: 796.879061239893 }, - { x: 754.3712603631087, y: 796.879061239893 }, - { x: 754.3712603631087, y: 196.46989831140326 }, - { x: 403.962097434619, y: 196.46989831140326 }, - { x: 403.962097434619, y: 446.46989831140326 }, + { x: 150, y: 450 }, + { x: 150, y: 800 }, + { x: 750, y: 800 }, + { x: 750, y: 300 }, + { x: 550, y: 300 }, + { x: 550, y: 450 }, ] if (canvas) { const polygon = new QPolygon( - type3, + type1, { fill: 'transparent', stroke: 'black', diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 7fbe9d4a..a2a78fda 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -30,7 +30,6 @@ export default class QPolygon extends fabric.Group { } const sortPoints = sortedPoints(points) - console.log(sortPoints) const polygon = new fabric.Polygon(sortPoints, options) super([polygon], {}) @@ -321,7 +320,9 @@ export default class QPolygon extends fabric.Group { return } //외각선 기준 - const topIndex = findTopTwoIndexesByDistance(this.lines) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 + const topIndex = findTopTwoIndexesByDistance(this.lines).sort( + (a, b) => a - b, + ) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 //일단 배열 6개 짜리 기준의 선 번호 if (topIndex[0] === 4) { @@ -639,7 +640,7 @@ export default class QPolygon extends fabric.Group { y: (lines[1].y1 + lines[1].y2) / 2, } - ridgeLength = Math.min(this.lines[2].length, this.lines[5].length) + ridgeLength = Math.min(this.lines[4].length, this.lines[5].length) ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x + ridgeLength, vPoint1.y] ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y + ridgeLength] } @@ -694,7 +695,7 @@ export default class QPolygon extends fabric.Group { // 용마루 보조선 const ridgeHelpLine1 = new QLine( - [lines2[1].x2, lines2[1].y2, ridgePoint1[2], ridgePoint1[3]], + [lines2[0].x2, lines2[0].y2, ridgePoint1[2], ridgePoint1[3]], { fontSize: this.fontSize, stroke: 'black', @@ -705,7 +706,7 @@ export default class QPolygon extends fabric.Group { // 용마루 보조선 const ridgeHelpLine2 = new QLine( - [lines2[0].x2, lines2[0].y2, ridgePoint2[2], ridgePoint2[3]], + [lines2[1].x2, lines2[1].y2, ridgePoint2[2], ridgePoint2[3]], { fontSize: this.fontSize, stroke: 'black', @@ -751,7 +752,6 @@ export default class QPolygon extends fabric.Group { this.addWithUpdate(ridgeEndLine) this.canvas.renderAll() - console.log(JSON.stringify(this.points)) } #drawHelpLineInOctagon(chon) {} From a7c0e27f675e7995fb600adaa2897c3785e9f334 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 16 Jul 2024 16:35:30 +0900 Subject: [PATCH 103/113] feat: Add template buttons for different patterns in Roof2 component --- src/components/Roof2.jsx | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 3dbfc5c7..1aa80094 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -270,7 +270,21 @@ export default function Roof2() { color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEMPLATE)} > - 템플릿 + 템플릿(기둥) + + + @@ -356,8 +363,21 @@ export default function Roof2() { +
-
+
{ + const firstPoint = historyPoints.current[0] + const lastPoint = historyPoints.current[historyPoints.current.length - 1] + historyPoints.current.forEach((point) => { + canvas?.remove(point) + }) + drawLineWithLength(lastPoint, firstPoint) + points.current = [] + historyPoints.current = [] + + // handleOuterlines() + const wall = makePolygon() + setWall(wall) + + return wall + } + const templateMode = () => { changeMode(canvas, Mode.EDIT) if (historyPoints.current.length >= 4) { - const firstPoint = historyPoints.current[0] - const lastPoint = historyPoints.current[historyPoints.current.length - 1] - historyPoints.current.forEach((point) => { - canvas?.remove(point) - }) - drawLineWithLength(lastPoint, firstPoint) - points.current = [] - historyPoints.current = [] + drawWallPolygon() + //아래 내용 drawWallPolygon()으로 대체 + // const firstPoint = historyPoints.current[0] + // const lastPoint = historyPoints.current[historyPoints.current.length - 1] + // historyPoints.current.forEach((point) => { + // canvas?.remove(point) + // }) + // drawLineWithLength(lastPoint, firstPoint) + // points.current = [] + // historyPoints.current = [] + + // // handleOuterlines() + // const wall = makePolygon() + // setWall(wall) - // handleOuterlines() handleOuterlinesTest() //외곽선 그리기 테스트 - - const wall = makePolygon() - setWall(wall) } } @@ -895,6 +921,171 @@ export function useMode() { return rtnLines } + /** + * 템플릿 B 적용 + * 1. 모드 체인지 + * 2. 외벽선 그리기 마무리 + */ + const applyTemplateB = () => { + changeMode(canvas, Mode.EDIT) + const polygon = drawWallPolygon() + handleOuterLineTemplateB(polygon) + } + + const handleOuterLineTemplateB = (polygon) => { + polygon.points.forEach((point, index) => { + let x2 = + index === polygon.points.length - 1 + ? 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 y1 = point.y + if (index % 2 === 0) { + if (polygon.lines[index].direction === 'bottom') { + y1 = y1 - 50 + y2 = y2 + 50 + x1 = x1 - 20 + x2 = x2 - 20 + } else { + y1 = y1 + 50 + y2 = y2 - 50 + x1 = x1 + 20 + x2 = x2 + 20 + } + } else { + if (polygon.lines[index].direction === 'right') { + x1 = x1 - 20 + x2 = x2 + 20 + y1 = y1 + 50 + y2 = y2 + 50 + } else { + x1 = x1 + 20 + x2 = x2 - 20 + y1 = y1 - 50 + y2 = y2 - 50 + } + } + + switch (polygon.shape) { + case 1: + 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 - 20, + polygon.points[0].y + + (polygon.points[1].y - polygon.points[0].y) / 2, + polygon.points[5].x + 20, + 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 === 3) { + x2 = x2 + 20 + + const subLine = new QLine([x2, y2, x2, centerPoint], { + stroke: 'blue', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, + }) + canvas.add(subLine) + } + if (index === 4) { + y1 = + point.y + + (polygon.points[index - 2].y - polygon.points[index - 1].y) / 2 + + const subLine = new QLine( + [point.x, centerPoint, polygon.points[2].x + 20, centerPoint], + { + stroke: 'blue', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, + }, + ) + canvas.add(subLine) + + const subVerticalLine = new QLine( + [ + getCenterPoint(point.x, polygon.points[2].x + 20), + polygon.points[3].y - 50, + getCenterPoint(point.x, polygon.points[2].x + 20), + centerPoint, + ], + { + stroke: 'black', + strokeWidth: 2, + strokeDashArray: [5, 5], + selectable: false, + fontSize: fontSize, + }, + ) + canvas.add(subVerticalLine) + } + + if (index === 5) { + const centeredPoint = getCenterPoint( + polygon.points[0].x, + polygon.points[5].x, + ) + const verticalSubLine = new QLine( + [ + centeredPoint, + 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) + } + + break + case 3: + break + case 4: + break + default: + break + } + + const line = new QLine([x1, y1, x2, y2], { + stroke: 'blue', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, + }) + canvas.add(line) + }) + canvas.renderAll() + } + return { mode, changeMode, @@ -905,5 +1096,6 @@ export function useMode() { zoom, togglePolygonLine, handleOuterlinesTest2, + applyTemplateB, } } diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 84563f34..e1c4b0fa 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -74,6 +74,24 @@ export function anchorWrapper(anchorIndex, fn) { } } +/** + * 두 좌표의 중간점 좌표를 계산해서 반환하는 함수 + * @param {number} point1 + * @param {number} point2 방향에 상관없이 항상 큰 값이 뒤에 위치해야 함 + * @returns + */ +export const getCenterPoint = (point1, point2) => { + return point1 + (point2 - point1) / 2 +} + +/** + * 두 점 사이의 거리를 계산하는 함수 + * @param {*} x1 첫번째 점 x좌표 + * @param {*} y1 첫번째 점 y좌표 + * @param {*} x2 두번째 점 x좌표 + * @param {*} y2 두번째 점 y좌표 + * @returns + */ export const getDistance = (x1, y1, x2, y2) => { return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) } From 64e69f2c0d254027f8c237535632e7d25dee8966 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 17 Jul 2024 14:06:49 +0900 Subject: [PATCH 112/113] =?UTF-8?q?=EB=B3=B4=EC=A1=B0=EC=84=A0=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 14 +-- src/components/fabric/QPolygon.js | 178 +++++++++++++++++++++++++----- 2 files changed, 158 insertions(+), 34 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 1aa80094..5854523e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -151,12 +151,12 @@ export default function Roof2() { ] const type3 = [ - { x: 200, y: 150 }, - { x: 200, y: 650 }, - { x: 450, y: 650 }, - { x: 450, y: 500 }, - { x: 650, y: 500 }, - { x: 650, y: 150 }, + { 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 = [ @@ -169,7 +169,7 @@ export default function Roof2() { ] if (canvas) { const polygon = new QPolygon( - type1, + type4, { fill: 'transparent', stroke: 'black', diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 512149f3..93d39298 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -326,7 +326,7 @@ export default class QPolygon extends fabric.Group { this.canvas.requestRenderAll() } - // 보조선 그리기 사각형에서만 + // 보조선 그리기 drawHelpLine(chon = 4) { if (!this.isValid()) { return @@ -580,12 +580,25 @@ export default class QPolygon extends fabric.Group { // 용마루 시작점과 만나는 지붕의 중앙 let centerPoint1, centerPoint2 + // 가장 긴 라인 + let longestLines + // 용마루 길이 let ridgeLength = 0 - let ridgePoint1, ridgePoint2 + let ridgeStartPoint1, ridgeStartPoint2 + + let ridgeEndPoint1, ridgeEndPoint2 + + let ridgeLength1, ridgeLength2 + + let ridgeHelpLinePoint1, ridgeHelpLinePoint2 + if (type === 1) { lines = [this.lines[0], this.lines[3]] lines2 = [this.lines[1], this.lines[4]] + longestLines = [this.lines[4], this.lines[5]] + ridgeLength1 = lines2[0].length + ridgeLength2 = longestLines[0].length - lines[1].length vPoint1 = { x: lines[0].x1 + lines[0].length / 2, y: lines[0].y1 + lines[0].length / 2, @@ -603,12 +616,37 @@ export default class QPolygon extends fabric.Group { y: (lines[1].y1 + lines[1].y2) / 2, } - ridgeLength = Math.min(this.lines[1].length, this.lines[2].length) - ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x + ridgeLength, vPoint1.y] - ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y - ridgeLength] + ridgeEndPoint1 = [ + vPoint1.x, + vPoint1.y, + vPoint1.x + ridgeLength1, + vPoint1.y, + ] + ridgeEndPoint2 = [ + vPoint2.x, + vPoint2.y, + vPoint2.x, + vPoint2.y - ridgeLength2, + ] + + ridgeHelpLinePoint1 = [ + lines2[0].x2, + lines2[0].y2, + ridgeEndPoint1[2], + ridgeEndPoint1[3], + ] + ridgeHelpLinePoint2 = [ + lines2[1].x2, + lines2[1].y2, + ridgeEndPoint2[2], + ridgeEndPoint2[3], + ] } else if (type === 2) { lines = [this.lines[2], this.lines[5]] lines2 = [this.lines[0], this.lines[3]] + longestLines = [this.lines[0], this.lines[1]] + ridgeLength1 = lines2[1].length + ridgeLength2 = longestLines[0].length - lines[1].length vPoint1 = { x: lines[0].x1 - lines[0].length / 2, y: lines[0].y1 - lines[0].length / 2, @@ -626,12 +664,38 @@ export default class QPolygon extends fabric.Group { y: (lines[1].y1 + lines[1].y2) / 2, } - ridgeLength = Math.min(this.lines[3].length, this.lines[4].length) - ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x - ridgeLength, vPoint1.y] - ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y + ridgeLength] + ridgeEndPoint1 = [ + vPoint1.x, + vPoint1.y, + vPoint1.x - ridgeLength1, + vPoint1.y, + ] + + ridgeEndPoint2 = [ + vPoint2.x, + vPoint2.y, + vPoint2.x, + vPoint2.y + ridgeLength2, + ] + + ridgeHelpLinePoint1 = [ + lines2[1].x2, + lines2[1].y2, + ridgeEndPoint1[2], + ridgeEndPoint1[3], + ] + ridgeHelpLinePoint2 = [ + lines2[0].x2, + lines2[0].y2, + ridgeEndPoint2[2], + ridgeEndPoint2[3], + ] } else if (type === 3) { lines = [this.lines[1], this.lines[4]] lines2 = [this.lines[2], this.lines[5]] + longestLines = [this.lines[0], this.lines[5]] + ridgeLength1 = this.lines[3].length + ridgeLength2 = longestLines[0].length - lines[0].length vPoint1 = { x: lines[0].x1 + lines[0].length / 2, y: lines[0].y1 - lines[0].length / 2, @@ -649,12 +713,38 @@ export default class QPolygon extends fabric.Group { y: (lines[1].y1 + lines[1].y2) / 2, } - ridgeLength = Math.min(this.lines[2].length, this.lines[3].length) - ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x, vPoint1.y - ridgeLength] - ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x - ridgeLength, vPoint2.y] + ridgeEndPoint1 = [ + vPoint1.x, + vPoint1.y, + vPoint1.x, + vPoint1.y - ridgeLength2, + ] + + ridgeEndPoint2 = [ + vPoint2.x, + vPoint2.y, + vPoint2.x - ridgeLength1, + vPoint2.y, + ] + + ridgeHelpLinePoint1 = [ + lines2[1].x2, + lines2[1].y2, + ridgeEndPoint1[2], + ridgeEndPoint1[3], + ] + ridgeHelpLinePoint2 = [ + lines2[0].x2, + lines2[0].y2, + ridgeEndPoint2[2], + ridgeEndPoint2[3], + ] } else if (type === 4) { lines = [this.lines[0], this.lines[3]] lines2 = [this.lines[1], this.lines[4]] + longestLines = [this.lines[1], this.lines[2]] + ridgeLength1 = longestLines[0].length - lines[0].length + ridgeLength2 = this.lines[4].length vPoint1 = { x: lines[0].x1 + lines[0].length / 2, y: lines[0].y1 + lines[0].length / 2, @@ -672,9 +762,32 @@ export default class QPolygon extends fabric.Group { y: (lines[1].y1 + lines[1].y2) / 2, } - ridgeLength = Math.min(this.lines[4].length, this.lines[5].length) - ridgePoint1 = [vPoint1.x, vPoint1.y, vPoint1.x + ridgeLength, vPoint1.y] - ridgePoint2 = [vPoint2.x, vPoint2.y, vPoint2.x, vPoint2.y + ridgeLength] + ridgeEndPoint1 = [ + vPoint1.x, + vPoint1.y, + vPoint1.x + ridgeLength1, + vPoint1.y, + ] + + ridgeEndPoint2 = [ + vPoint2.x, + vPoint2.y, + vPoint2.x, + vPoint2.y + ridgeLength2, + ] + + ridgeHelpLinePoint1 = [ + lines2[0].x2, + lines2[0].y2, + ridgeEndPoint1[2], + ridgeEndPoint1[3], + ] + ridgeHelpLinePoint2 = [ + lines2[1].x2, + lines2[1].y2, + ridgeEndPoint2[2], + ridgeEndPoint2[3], + ] } const realLine1 = new QLine( @@ -727,7 +840,7 @@ export default class QPolygon extends fabric.Group { // 용마루 보조선 const ridgeHelpLine1 = new QLine( - [lines2[0].x2, lines2[0].y2, ridgePoint1[2], ridgePoint1[3]], + ridgeHelpLinePoint1, { fontSize: this.fontSize, stroke: 'blue', @@ -738,7 +851,7 @@ export default class QPolygon extends fabric.Group { // 용마루 보조선 const ridgeHelpLine2 = new QLine( - [lines2[1].x2, lines2[1].y2, ridgePoint2[2], ridgePoint2[3]], + ridgeHelpLinePoint2, { fontSize: this.fontSize, stroke: 'blue', @@ -748,21 +861,32 @@ export default class QPolygon extends fabric.Group { ) // 용마루 - const ridge1 = new QLine(ridgePoint1, { - fontSize: this.fontSize, - stroke: 'blue', - strokeWidth: 1, - }) + const ridge1 = new QLine( + [vPoint1.x, vPoint1.y, ridgeEndPoint1[2], ridgeEndPoint1[3]], + { + fontSize: this.fontSize, + stroke: 'blue', + strokeWidth: 1, + }, + ) // 용마루 - const ridge2 = new QLine(ridgePoint2, { - fontSize: this.fontSize, - stroke: 'blue', - strokeWidth: 1, - }) + const ridge2 = new QLine( + [vPoint2.x, vPoint2.y, ridgeEndPoint2[2], ridgeEndPoint2[3]], + { + fontSize: this.fontSize, + stroke: 'blue', + strokeWidth: 1, + }, + ) const ridgeEndLine = new QLine( - [ridgePoint1[2], ridgePoint1[3], ridgePoint2[2], ridgePoint2[3]], + [ + ridgeEndPoint1[2], + ridgeEndPoint1[3], + ridgeEndPoint2[2], + ridgeEndPoint2[3], + ], { fontSize: this.fontSize, stroke: 'blue', From 01f969518d7539f44034b7ac2cac7baf6f652ee9 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 17 Jul 2024 14:08:25 +0900 Subject: [PATCH 113/113] chore: Update page layout for Roof2 --- src/app/roof2/page.jsx | 3 +-- src/components/Roof2.jsx | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx index 81eaaec4..8c83730e 100644 --- a/src/app/roof2/page.jsx +++ b/src/app/roof2/page.jsx @@ -15,8 +15,7 @@ export default function Roof2Page() { return ( <> - -
+
diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 1f81ee41..708b58f0 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -418,7 +418,7 @@ export default function Roof2() {
)} -
+