Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2024-08-02 17:09:05 +09:00
commit 9dffc30797
18 changed files with 190 additions and 216 deletions

Binary file not shown.

BIN
Qcast coding convention.pdf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,19 +1,36 @@
# 점 갯수 별 타입
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).
## 점 6개
## Getting Started
### type1
First, run the development server:
![type1](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6+-+type1.png)
```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.
![type2](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-+type2.png)
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
### type3
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
![type3](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-type3.png)
## Learn More
### type4
To learn more about Next.js, take a look at the following resources:
![type4](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-type4.png)
- [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.

View File

@ -10,6 +10,9 @@ const nextConfig = {
// config.infrastructureLogging = { debug: /PackFileCache/ };
return config
},
sassOptions: {
includePaths: ['./src/styles'],
},
}
export default nextConfig

View File

@ -26,6 +26,7 @@
"postcss": "^8",
"prettier": "^3.3.3",
"prisma": "^5.17.0",
"sass": "^1.77.8",
"tailwindcss": "^3.4.1"
}
}

19
shape-type.md Normal file
View File

@ -0,0 +1,19 @@
# 점 갯수 별 타입
## 점 6개
### type1
![type1](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6+-+type1.png)
### type2
![type2](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-+type2.png)
### type3
![type3](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-type3.png)
### type4
![type4](https://devgrr-bucket.s3.ap-northeast-2.amazonaws.com/qcast-type/point6-type4.png)

View File

@ -47,6 +47,9 @@ export default function changelogPage() {
<Button onClick={handleUsers}>Button</Button>
</div>
</div>
<div className="test">
<p className="text-white">Sass 테스트입니다.</p>
</div>
</>
)
}

View File

@ -1,5 +1,6 @@
import { Inter } from 'next/font/google'
import './globals.css'
import '../styles/style.scss'
import Headers from '@/components/Headers'
import RecoilRootWrapper from './RecoilWrapper'
import UIProvider from './UIProvider'

View File

@ -2,11 +2,10 @@ import { useCanvas } from '@/hooks/useCanvas'
import { useEffect, useState } from 'react'
import { Mode, useMode } from '@/hooks/useMode'
import { Button } from '@nextui-org/react'
import QRect from '@/components/fabric/QRect'
import RangeSlider from './ui/RangeSlider'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasSizeState, fontSizeState, roofMaterialState, roofState, sortedPolygonArray } from '@/store/canvasAtom'
import { canvasSizeState, fontSizeState, roofMaterialState, sortedPolygonArray } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
import { calculateIntersection } from '@/util/canvas-util'
@ -60,22 +59,6 @@ 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,
fontSize: fontSize,
})
canvas?.add(rect)
}
}
const makeLine = () => {
if (canvas) {
const line = new QLine([50, 50, 200, 50], {
@ -265,7 +248,7 @@ export default function Roof2() {
{ x: 675, y: 275 },
{ x: 450, y: 850 },
]
const polygon = new QPolygon(type2, {
const polygon = new QPolygon(type1, {
fill: 'transparent',
stroke: 'black',
strokeWidth: 1,
@ -451,28 +434,34 @@ export default function Roof2() {
const createRoofRack = () => {
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
roofs.forEach((roof) => {
roofs.forEach((roof, index) => {
let maxLengthLine = roof.lines.reduce((acc, cur) => {
return acc.length > cur.length ? acc : cur
})
const offsetPolygonPoint = offsetPolygon(roof.points, -20, 0)
const newPoly = new QPolygon(offsetPolygonPoint, {
const trestlePoly = new QPolygon(offsetPolygonPoint, {
fill: 'transparent',
stroke: 'red',
strokeWidth: 1,
selectable: true,
fontSize: fontSize,
name: 'wall',
name: 'trestle',
lockMovementX: true, // X
lockMovementY: true, // Y
lockRotation: true, //
lockScalingX: true, // X
lockScalingY: true, // Y
idx: index,
})
canvas?.add(newPoly)
canvas?.add(trestlePoly)
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
newPoly.fillCell({ width: 100, height: 50, padding: 10 })
trestlePoly.fillCell({ width: 100, height: 50, padding: 10 })
} else {
newPoly.fillCell({ width: 50, height: 100, padding: 10 })
trestlePoly.fillCell({ width: 50, height: 100, padding: 10 })
}
})
}
@ -515,9 +504,6 @@ export default function Roof2() {
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => setMode(Mode.TEXTBOX)}>
텍스트박스 모드
</Button>
<Button className="m-1 p-2" color={`${mode === Mode.DRAW_RECT ? 'primary' : 'default'}`} onClick={() => setMode(Mode.DRAW_RECT)}>
사각형 생성 모드
</Button>
<Button className="m-1 p-2" onClick={handleUndo}>
Undo
</Button>
@ -534,9 +520,6 @@ export default function Roof2() {
축소
</Button>
현재 : {zoom}%
<Button className="m-1 p-2" onClick={makeRect}>
사각형만들기
</Button>
<Button className="m-1 p-2" onClick={makeLine}>
추가
</Button>

View File

@ -255,10 +255,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
name: 'cell',
})
rect.on('mousedown', () => {
rect.set({ fill: 'red' })
})
drawCellsArray.push(rect) //배열에 넣어서 반환한다
this.canvas.add(rect)
}

View File

@ -1,98 +0,0 @@
import { fabric } from 'fabric'
export default class QRect extends fabric.Rect {
#text = []
#viewLengthText
#fontSize
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(option) {
this.#viewLengthText = option.viewLengthText ?? true
}
setViewLengthText(bool) {
this.#viewLengthText = bool
this.#addLengthText()
}
setFontSize(fontSize) {
this.#fontSize = fontSize
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) => {
this.#addLengthText()
})
this.on('scaling', (e) => {
this.#addLengthText()
})
this.on('moving', () => {
this.#addLengthText()
})
}
#addLengthText() {
if (this.#text.length > 0) {
this.#text.forEach((text) => {
this.canvas.remove(text)
})
this.#text = []
}
if (!this.#viewLengthText) {
return
}
const scaleX = this.scaleX
const scaleY = this.scaleY
const lines = [
{
start: { x: this.left, y: this.top },
end: { x: this.left + this.width * scaleX, y: this.top },
},
{
start: { x: this.left, y: this.top + this.height * scaleY },
end: { x: this.left, y: this.top },
},
]
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: this.#fontSize,
selectable: false,
})
this.#text.push(text)
this.canvas.add(text)
})
}
}

View File

@ -5,7 +5,6 @@ import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/can
import { useRecoilState } from 'recoil'
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
import QRect from '@/components/fabric/QRect'
import { QPolygon } from '@/components/fabric/QPolygon'
import { defineQLine } from '@/util/qline-utils'
import { defineQPloygon } from '@/util/qpolygon-utils'
@ -65,6 +64,7 @@ export function useCanvas(id) {
if (canvas) {
initialize()
canvas?.on('object:added', onChange)
canvas?.on('object:added', addEventOnObject)
canvas?.on('object:modified', onChange)
canvas?.on('object:removed', onChange)
canvas?.on('mouse:move', drawMouseLines)
@ -93,6 +93,21 @@ export function useCanvas(id) {
canvas?.off('mouse:down', handleMouseDown)
}
const addEventOnObject = (e) => {
const target = e.target
if (target.name === 'cell') {
target.on('mousedown', () => {
target.set({ fill: 'red' })
})
}
if (target.name === 'trestle') {
target.on('mousedown', () => {
target.set({ strokeWidth: 5 })
})
}
}
/**
* 마우스 포인터의 가이드라인을 제거합니다.
*/
@ -116,7 +131,6 @@ export function useCanvas(id) {
fabric.QPolygon = QPolygon
QPolygon.prototype.canvas = canvas
QLine.prototype.canvas = canvas
QRect.prototype.canvas = canvas
defineQLine()
defineQPloygon()
}

View File

@ -1,5 +1,4 @@
import { useEffect, useRef, useState } from 'react'
import QRect from '@/components/fabric/QRect'
import { findTopTwoIndexesByDistance, getCenterPoint, getDirection, getStartIndex, rearrangeArray } from '@/util/canvas-util'
import { useRecoilState } from 'recoil'
@ -615,27 +614,6 @@ export function useMode() {
rect.set({ width: Math.abs(origX - pointer.x) })
rect.set({ height: Math.abs(origY - pointer.y) })
})
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,
viewLengthText: true,
fill: 'transparent',
stroke: 'black',
transparentCorners: false,
fontSize: fontSize,
})
canvas.remove(rect)
canvas.add(qRect)
isDown = false
})
}
/**
@ -1113,8 +1091,8 @@ export function useMode() {
/**
* 지붕 외곽선 생성 polygon을 입력받아 만들기
*/
const handleOuterlinesTest2 = (polygon, offset = 71) => {
const offsetPoints = offsetPolygon(polygon.points, 50)
const handleOuterlinesTest2 = (polygon, offset = 50) => {
const offsetPoints = offsetPolygon(polygon.points, offset)
const roof = makePolygon(
offsetPoints.map((point) => {

3
src/styles/_test.scss Normal file
View File

@ -0,0 +1,3 @@
.test {
background-color: #121212;
}

1
src/styles/style.scss Normal file
View File

@ -0,0 +1 @@
@import '_test.scss';

View File

@ -253,6 +253,10 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
name: 'hip',
})
if (line.length === 0) {
return
}
line.startPoint = ridgePoint
line.endPoint = filteredCenterInterSectionPoints
@ -283,54 +287,74 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
const startPoint = remainingPoints.shift()
const endPoint = remainingPoints.shift()
const line = new QLine([startPoint.x, startPoint.y, endPoint.x, endPoint.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'connectRidge',
})
if (!(startPoint.x === endPoint.x && startPoint.y === endPoint.y)) {
const line = new QLine([startPoint.x, startPoint.y, endPoint.x, endPoint.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'connectRidge',
})
line.startPoint = startPoint
line.endPoint = endPoint
line.startPoint = startPoint
line.endPoint = endPoint
polygon.connectRidges.push(line)
polygon.connectRidges.push(line)
polygon.points.forEach((point) => {
const degree = calculateAngle(startPoint, point)
polygon.points.forEach((point) => {
const degree = calculateAngle(startPoint, point)
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
const line = new QLine([startPoint.x, startPoint.y, point.x, point.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'hip',
})
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
const line = new QLine([startPoint.x, startPoint.y, point.x, point.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'hip',
})
line.startPoint = startPoint
line.endPoint = point
line.startPoint = startPoint
line.endPoint = point
polygon.hips.push(line)
polygon.canvas.add(line)
}
})
polygon.hips.push(line)
polygon.canvas.add(line)
}
})
polygon.points.forEach((point) => {
const degree = calculateAngle(endPoint, point)
polygon.points.forEach((point) => {
const degree = calculateAngle(endPoint, point)
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
const line = new QLine([endPoint.x, endPoint.y, point.x, point.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'hip',
})
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
const line = new QLine([endPoint.x, endPoint.y, point.x, point.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'hip',
})
line.startPoint = endPoint
line.endPoint = point
line.startPoint = endPoint
line.endPoint = point
polygon.hips.push(line)
polygon.canvas.add(line)
}
})
polygon.hips.push(line)
polygon.canvas.add(line)
}
})
polygon.canvas.add(line)
polygon.canvas.add(line)
} else {
polygon.points.forEach((point) => {
const degree = calculateAngle(startPoint, point)
if (Math.abs(degree) === 45 || Math.abs(degree) === 135) {
const line = new QLine([startPoint.x, startPoint.y, point.x, point.y], {
stroke: 'purple',
fontSize: polygon.fontSize,
name: 'hip',
})
line.startPoint = startPoint
line.endPoint = point
polygon.hips.push(line)
polygon.canvas.add(line)
}
})
}
}
}
@ -485,9 +509,8 @@ export const dividePolygon = (polygon) => {
}
})
hips = [...hips, ...connectRidges]
polygon.setViewLengthText(false)
polygonLines.forEach((line) => {
polygonLines.forEach((line, index) => {
let ridge
const startPoint = line.startPoint
@ -522,15 +545,31 @@ export const dividePolygon = (polygon) => {
return
}
let connectedRidge = ridges.find(
(ridge) =>
(ridge.startPoint.x === startHip.endPoint.x && ridge.startPoint.y === startHip.endPoint.y) ||
(ridge.endPoint.x === startHip.endPoint.x && ridge.endPoint.y === startHip.endPoint.y),
)
let connectedRidge
const restRidgeConnection = connectRidges[0]
if (!restRidgeConnection || restRidgeConnection.length === 0) {
connectedRidge = ridges.find(
(ridge) =>
(ridge.startPoint.x === startHip.endPoint.x &&
ridge.startPoint.y === startHip.endPoint.y &&
ridge.endPoint.x === endHip.endPoint.x &&
ridge.endPoint.y === endHip.endPoint.y) ||
(ridge.startPoint.x === endHip.endPoint.x &&
ridge.startPoint.y === endHip.endPoint.y &&
ridge.endPoint.x === startHip.endPoint.x &&
ridge.endPoint.y === startHip.endPoint.y),
)
} else {
connectedRidge = ridges.find(
(ridge) =>
(ridge.startPoint.x === startHip.endPoint.x && ridge.startPoint.y === startHip.endPoint.y) ||
(ridge.endPoint.x === startHip.endPoint.x && ridge.endPoint.y === startHip.endPoint.y),
)
}
const hipStartPoint = startHip.endPoint
const hipEndPoint = endHip.endPoint
const restRidgeConnection = connectRidges[0]
if (connectedRidge.startPoint.x === hipStartPoint.x && connectedRidge.startPoint.y === hipStartPoint.y) {
if (connectedRidge.endPoint.x === hipEndPoint.x && connectedRidge.endPoint.y === hipEndPoint.y) {

View File

@ -2258,7 +2258,7 @@ canvas@^2.8.0:
nan "^2.17.0"
simple-get "^3.0.3"
chokidar@^3.5.3:
"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3:
version "3.6.0"
resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz"
integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==
@ -2714,6 +2714,11 @@ iconv-lite@0.6.3:
dependencies:
safer-buffer ">= 2.1.2 < 3.0.0"
immutable@^4.0.0:
version "4.3.7"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.7.tgz#c70145fc90d89fb02021e65c84eb0226e4e5a381"
integrity sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
@ -3402,6 +3407,15 @@ safe-buffer@~5.2.0:
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
sass@^1.77.8:
version "1.77.8"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.77.8.tgz#9f18b449ea401759ef7ec1752a16373e296b52bd"
integrity sha512-4UHg6prsrycW20fqLGPShtEvo/WyHRVRHwOP4DzkUrObWoWI05QBSfzU71TVB7PFaL104TwNaHpjlWXAZbQiNQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
saxes@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz"
@ -3486,7 +3500,7 @@ simple-swizzle@^0.2.2:
dependencies:
is-arrayish "^0.3.1"
source-map-js@^1.0.2, source-map-js@^1.2.0:
"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz"
integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==