Merge branch 'feature/test'
This commit is contained in:
commit
8d944afb0c
12
.env
Normal file
12
.env
Normal file
@ -0,0 +1,12 @@
|
||||
# Environment variables declared in this file are automatically made available to Prisma.
|
||||
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
|
||||
|
||||
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
|
||||
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
|
||||
|
||||
# DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
|
||||
# DATABASE_URL="mongodb://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/sample_mflix?retryWrites=true&w=majority"
|
||||
#DATABASE_URL = "mongodb%2Bsrv%3A%2F%2Fyoo32767%3AGuCtswjLGqUaNL0G%40cluster0.vsdtcnb.mongodb.net%2F%3FretryWrites%3Dtrue%26w%3Dmajority%26appName%3DCluster0"
|
||||
# DATABASE_URL = "mongodb+srv://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/Cluster0?retryWrites=true&w=majority"
|
||||
# DATABASE_URL="mongodb://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/sample_mflix?retryWrites=true&w=majority"
|
||||
DATABASE_URL="mongodb+srv://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/mytest"
|
||||
@ -10,9 +10,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@nextui-org/react": "^2.4.2",
|
||||
"@prisma/client": "^5.17.0",
|
||||
"fabric": "^5.3.0",
|
||||
"framer-motion": "^11.2.13",
|
||||
"mathjs": "^13.0.2",
|
||||
"mongodb": "^6.8.0",
|
||||
"next": "14.2.3",
|
||||
"react": "^18",
|
||||
"react-dom": "^18",
|
||||
@ -21,6 +23,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"postcss": "^8",
|
||||
"prisma": "^5.17.0",
|
||||
"tailwindcss": "^3.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
19
prisma/schema.prisma
Normal file
19
prisma/schema.prisma
Normal file
@ -0,0 +1,19 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "mongodb"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model test {
|
||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
||||
content String
|
||||
}
|
||||
|
||||
model canvas {
|
||||
id String @id @default(auto()) @map("_id") @db.ObjectId
|
||||
loginId String
|
||||
canvas Json
|
||||
}
|
||||
@ -7,11 +7,13 @@ import QPolygon from '@/components/fabric/QPolygon'
|
||||
|
||||
import RangeSlider from './ui/RangeSlider'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
|
||||
import { canvasAtom, canvasListState, canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
import { getTests, getCanvasState, insertCanvasState } from '@/lib/canvas'
|
||||
import { calculateIntersection2 } from '@/util/canvas-util'
|
||||
|
||||
export default function Roof2() {
|
||||
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage } = useCanvas('canvas')
|
||||
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
||||
|
||||
//canvas 기본 사이즈
|
||||
const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
|
||||
@ -29,8 +31,22 @@ export default function Roof2() {
|
||||
|
||||
const [showControl, setShowControl] = useState(false)
|
||||
|
||||
const { mode, changeMode, handleClear, fillCellInPolygon, zoomIn, zoomOut, zoom, togglePolygonLine, handleOuterlinesTest2, applyTemplateB } =
|
||||
useMode()
|
||||
const {
|
||||
mode,
|
||||
changeMode,
|
||||
handleClear,
|
||||
fillCellInPolygon,
|
||||
zoomIn,
|
||||
zoomOut,
|
||||
zoom,
|
||||
togglePolygonLine,
|
||||
handleOuterlinesTest,
|
||||
handleOuterlinesTest2,
|
||||
applyTemplateB,
|
||||
makeRoofPatternPolygon,
|
||||
} = useMode()
|
||||
|
||||
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvas) {
|
||||
@ -168,8 +184,31 @@ export default function Roof2() {
|
||||
{ x: 1088, y: 991 },
|
||||
{ x: 1088, y: 42 },
|
||||
]
|
||||
|
||||
const eightPoint = [
|
||||
{ x: 240, y: 130 },
|
||||
{ x: 240, y: 630 },
|
||||
{ x: 640, y: 630 },
|
||||
{ x: 640, y: 480 },
|
||||
{ x: 440, y: 480 },
|
||||
{ x: 440, y: 280 },
|
||||
{ x: 740, y: 280 },
|
||||
{ x: 740, y: 130 },
|
||||
]
|
||||
|
||||
const eightPoint2 = [
|
||||
{ x: 197, y: 215 },
|
||||
{ x: 197, y: 815 },
|
||||
{ x: 397, y: 815 },
|
||||
{ x: 397, y: 1115 },
|
||||
{ x: 697, y: 1115 },
|
||||
{ x: 697, y: 815 },
|
||||
{ x: 897, y: 815 },
|
||||
{ x: 897, y: 215 },
|
||||
]
|
||||
|
||||
if (canvas) {
|
||||
const polygon = new QPolygon(type1, {
|
||||
const polygon = new QPolygon(eightPoint, {
|
||||
fill: 'transparent',
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
@ -180,6 +219,8 @@ export default function Roof2() {
|
||||
|
||||
canvas?.add(polygon)
|
||||
|
||||
console.log(polygon)
|
||||
|
||||
handleOuterlinesTest2(polygon)
|
||||
|
||||
// const lines = togglePolygonLine(polygon)
|
||||
@ -201,16 +242,44 @@ export default function Roof2() {
|
||||
const makeQLine = () => {
|
||||
if (canvas) {
|
||||
const line = new QLine(
|
||||
[50, 50, 200, 50],
|
||||
[50, 250, 900, 250],
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
strokeWidth: 5,
|
||||
fontSize: fontSize,
|
||||
selectable: true,
|
||||
},
|
||||
50,
|
||||
)
|
||||
|
||||
const line2 = new QLine(
|
||||
[450, 450, 821, 78],
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 5,
|
||||
fontSize: fontSize,
|
||||
selectable: true,
|
||||
},
|
||||
50,
|
||||
)
|
||||
|
||||
canvas?.add(line)
|
||||
canvas?.add(line2)
|
||||
|
||||
const interSectionPoint = calculateIntersection2(line, line2)
|
||||
|
||||
if (interSectionPoint) {
|
||||
console.log(interSectionPoint)
|
||||
|
||||
const circle = new fabric.Circle({
|
||||
radius: 5,
|
||||
fill: 'red',
|
||||
left: interSectionPoint.x - 5,
|
||||
top: interSectionPoint.y - 5,
|
||||
})
|
||||
|
||||
canvas?.add(circle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,10 +305,44 @@ export default function Roof2() {
|
||||
const lines = togglePolygonLine(polygon)
|
||||
}
|
||||
|
||||
/**
|
||||
* canvas 내용 저장하기
|
||||
*/
|
||||
const handleSaveCanvas = async () => {
|
||||
// const jsonStr = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize']))
|
||||
const jsonObj = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize', 'lines']))
|
||||
console.log(jsonObj)
|
||||
|
||||
const param = {
|
||||
loginId: 'test',
|
||||
canvas: jsonObj,
|
||||
}
|
||||
console.log(param)
|
||||
|
||||
await insertCanvasState(param)
|
||||
handleClear()
|
||||
}
|
||||
|
||||
/**
|
||||
* canvas 내용 불러오기
|
||||
*/
|
||||
const handleLoadCanvas = async () => {
|
||||
const canvasStates = await getCanvasState()
|
||||
console.log(JSON.parse(canvasStates.canvas))
|
||||
canvas?.loadFromJSON(JSON.parse(canvasStates.canvas))
|
||||
}
|
||||
|
||||
/**
|
||||
* 컨트롤러 보이기/숨기기
|
||||
*/
|
||||
const handleShowController = () => {
|
||||
setShowControl(!showControl)
|
||||
}
|
||||
|
||||
const drawRoofPatterns = (roofStyle) => {
|
||||
makeRoofPatternPolygon(roofStyle)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{canvas && (
|
||||
@ -267,6 +370,12 @@ export default function Roof2() {
|
||||
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.PATTERNB)}>
|
||||
템플릿(B 패턴)
|
||||
</Button>
|
||||
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => drawRoofPatterns(1)}>
|
||||
지붕패턴1
|
||||
</Button>
|
||||
<Button className="m-1 p-2" color={`${mode === Mode.TEMPLATE ? 'primary' : 'default'}`} onClick={() => drawRoofPatterns(2)}>
|
||||
지붕패턴2
|
||||
</Button>
|
||||
<Button className="m-1 p-2" color={`${mode === Mode.TEXTBOX ? 'primary' : 'default'}`} onClick={() => changeMode(canvas, Mode.TEXTBOX)}>
|
||||
텍스트박스 모드
|
||||
</Button>
|
||||
@ -333,6 +442,15 @@ export default function Roof2() {
|
||||
<Button className="m-1 p-2" onClick={PolygonToLine}>
|
||||
PolygonToLine
|
||||
</Button>
|
||||
{/*<Button className="m-1 p-2" onClick={handleSaveCanvas}>
|
||||
canvas 내용 저장하기
|
||||
</Button>
|
||||
<Button className="m-1 p-2" onClick={handleLoadCanvas}>
|
||||
canvas 내용 불러오기
|
||||
</Button>*/}
|
||||
<Button className="m-1 p-2" onClick={addCanvas}>
|
||||
캔버스 추가
|
||||
</Button>
|
||||
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
|
||||
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
|
||||
</Button>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { fabric } from 'fabric'
|
||||
import { getDirection, getDirectionByPoint } from '@/util/canvas-util'
|
||||
|
||||
export class QLine extends fabric.Group {
|
||||
line
|
||||
@ -13,7 +14,14 @@ export class QLine extends fabric.Group {
|
||||
idx
|
||||
type = 'QLine'
|
||||
parent
|
||||
#lengthTxt = 0
|
||||
isAlreadyInterSection = false
|
||||
|
||||
interSectionPoints = []
|
||||
lengthTxt = 0
|
||||
|
||||
initPoints
|
||||
initOption
|
||||
initLengthTxt
|
||||
|
||||
constructor(points, option = { isActiveLengthText: true }, lengthTxt) {
|
||||
// 소수점 전부 제거
|
||||
@ -30,38 +38,43 @@ export class QLine extends fabric.Group {
|
||||
const line = new fabric.Line(points, { ...option, strokeWidth: 1 })
|
||||
super([line], {})
|
||||
|
||||
this.initPoints = points
|
||||
this.initOption = option
|
||||
this.initLengthTxt = lengthTxt
|
||||
|
||||
this.x1 = x1
|
||||
this.y1 = y1
|
||||
this.x2 = x2
|
||||
this.y2 = y2
|
||||
this.line = line
|
||||
this.fontSize = option.fontSize
|
||||
this.direction = option.direction
|
||||
this.direction = option.direction ?? getDirectionByPoint({ x: x1, y: y1 }, { x: x2, y: y2 })
|
||||
this.parent = option.parent
|
||||
this.idx = option.idx
|
||||
|
||||
if (lengthTxt > 0) {
|
||||
this.#lengthTxt = Number(lengthTxt)
|
||||
this.lengthTxt = Number(lengthTxt)
|
||||
}
|
||||
|
||||
option.isActiveLengthText ?? this.#init()
|
||||
this.#addControl()
|
||||
option.isActiveLengthText ?? this.init()
|
||||
this.addControl()
|
||||
}
|
||||
|
||||
#init() {
|
||||
this.#addLengthText(true)
|
||||
init() {
|
||||
this.addLengthText(true)
|
||||
}
|
||||
|
||||
#addControl() {
|
||||
addControl() {
|
||||
this.on('moving', () => {
|
||||
this.#addLengthText(false)
|
||||
this.addLengthText(false)
|
||||
})
|
||||
|
||||
this.on('modified', (e) => {
|
||||
this.#addLengthText(false)
|
||||
this.addLengthText(false)
|
||||
})
|
||||
|
||||
this.on('selected', () => {
|
||||
console.log(this)
|
||||
Object.keys(this.controls).forEach((controlKey) => {
|
||||
if (controlKey !== 'ml' && controlKey !== 'mr') {
|
||||
this.setControlVisible(controlKey, false)
|
||||
@ -70,19 +83,19 @@ export class QLine extends fabric.Group {
|
||||
})
|
||||
}
|
||||
|
||||
#addLengthText(isFirst) {
|
||||
addLengthText(isFirst) {
|
||||
if (this.text) {
|
||||
this.removeWithUpdate(this.text)
|
||||
this.text = null
|
||||
}
|
||||
|
||||
if (isFirst && this.#lengthTxt > 0) {
|
||||
const text = new fabric.Textbox(this.#lengthTxt.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.length = this.lengthTxt
|
||||
this.text = text
|
||||
this.addWithUpdate(text)
|
||||
return
|
||||
@ -112,4 +125,41 @@ export class QLine extends fabric.Group {
|
||||
this.text.set({ fontSize })
|
||||
this.addWithUpdate()
|
||||
}
|
||||
|
||||
fromObject(object, callback) {
|
||||
console.log('fromObject', object, callback)
|
||||
}
|
||||
|
||||
async = true
|
||||
|
||||
toObject(propertiesToInclude) {
|
||||
return fabric.util.object.extend(this.callSuper('toObject'), {
|
||||
length: this.length,
|
||||
line: this.line,
|
||||
text: this.text,
|
||||
fontSize: this.fontSize,
|
||||
x1: this.x1,
|
||||
y1: this.y1,
|
||||
x2: this.x2,
|
||||
y2: this.y2,
|
||||
direction: this.direction,
|
||||
idx: this.idx,
|
||||
type: this.type,
|
||||
parent: this.parent,
|
||||
isAlreadyInterSection: this.isAlreadyInterSection,
|
||||
interSectionPoints: this.interSectionPoints,
|
||||
lengthTxt: this.lengthTxt,
|
||||
setFontSize: this.setFontSize,
|
||||
addLengthText: this.addLengthText,
|
||||
init: this.init,
|
||||
addControl: this.addControl,
|
||||
initPoints: this.initPoints,
|
||||
initOption: this.initOption,
|
||||
initLengthTxt: this.initLengthTxt,
|
||||
})
|
||||
}
|
||||
|
||||
_set(key, value) {
|
||||
this.callSuper('_set', key, value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { fabric } from 'fabric'
|
||||
import {
|
||||
calculateIntersection,
|
||||
calculateIntersection2,
|
||||
distanceBetweenPoints,
|
||||
findClosestLineToPoint,
|
||||
findTopTwoIndexesByDistance,
|
||||
@ -11,6 +12,7 @@ import {
|
||||
sortedPoints,
|
||||
} from '@/util/canvas-util'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
import { drawHelpLineInHexagon2 } from '@/util/qpolygon-utils'
|
||||
|
||||
export default class QPolygon extends fabric.Group {
|
||||
type = 'QPolygon'
|
||||
@ -27,6 +29,10 @@ export default class QPolygon extends fabric.Group {
|
||||
helpLines = []
|
||||
|
||||
wall
|
||||
|
||||
initPoints
|
||||
initOption
|
||||
|
||||
constructor(points, options, canvas) {
|
||||
/*if (points.length !== 4 && points.length !== 6) {
|
||||
throw new Error('Points must be 4 or 6.')
|
||||
@ -44,19 +50,23 @@ export default class QPolygon extends fabric.Group {
|
||||
const sortPoints = sortedPoints(points)
|
||||
const polygon = new fabric.Polygon(sortPoints, options)
|
||||
|
||||
super([polygon], {})
|
||||
super([polygon], { selectable: false })
|
||||
|
||||
this.fontSize = options.fontSize
|
||||
this.points = sortPoints
|
||||
this.polygon = polygon
|
||||
this.name = options.name
|
||||
this.#init()
|
||||
this.#addEvent()
|
||||
this.#initLines()
|
||||
|
||||
this.initPoints = points
|
||||
this.initOption = options
|
||||
|
||||
this.init()
|
||||
this.addEvent()
|
||||
this.initLines()
|
||||
this.setShape()
|
||||
}
|
||||
|
||||
#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], {
|
||||
@ -70,13 +80,13 @@ export default class QPolygon extends fabric.Group {
|
||||
})
|
||||
}
|
||||
|
||||
#init() {
|
||||
this.#addLengthText()
|
||||
init() {
|
||||
this.addLengthText()
|
||||
}
|
||||
|
||||
#addEvent() {
|
||||
addEvent() {
|
||||
this.on('scaling', (e) => {
|
||||
this.#updateLengthText()
|
||||
this.updateLengthText()
|
||||
})
|
||||
|
||||
this.on('selected', function () {
|
||||
@ -106,10 +116,10 @@ export default class QPolygon extends fabric.Group {
|
||||
}
|
||||
})
|
||||
|
||||
this.addWithUpdate()
|
||||
this.canvas.add()
|
||||
}
|
||||
|
||||
#addLengthText() {
|
||||
addLengthText() {
|
||||
if (this.texts.length > 0) {
|
||||
this.texts.forEach((text) => {
|
||||
this.canvas.remove(text)
|
||||
@ -135,13 +145,13 @@ export default class QPolygon extends fabric.Group {
|
||||
})
|
||||
|
||||
this.texts.push(text)
|
||||
this.addWithUpdate(text)
|
||||
this.canvas.add(text)
|
||||
})
|
||||
|
||||
this.canvas.renderAll()
|
||||
}
|
||||
|
||||
#updateLengthText() {
|
||||
updateLengthText() {
|
||||
const points = this.getCurrentPoints()
|
||||
|
||||
points.forEach((start, i) => {
|
||||
@ -187,10 +197,10 @@ export default class QPolygon extends fabric.Group {
|
||||
new fabric.Point(rect.left + rect.width, rect.top + rect.height),
|
||||
]
|
||||
|
||||
const isInside = rectPoints.every((rectPoint) => this.inPolygon(rectPoint) && this.#distanceFromEdge(rectPoint) >= cell.padding)
|
||||
const isInside = rectPoints.every((rectPoint) => this.inPolygon(rectPoint) && this.distanceFromEdge(rectPoint) >= cell.padding)
|
||||
|
||||
if (isInside) {
|
||||
this.addWithUpdate(rect)
|
||||
this.canvas.add(rect)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -244,7 +254,7 @@ export default class QPolygon extends fabric.Group {
|
||||
return intersects % 2 === 1
|
||||
}
|
||||
|
||||
#distanceFromEdge(point) {
|
||||
distanceFromEdge(point) {
|
||||
const vertices = this.getCurrentPoints()
|
||||
let minDistance = Infinity
|
||||
|
||||
@ -316,14 +326,14 @@ export default class QPolygon extends fabric.Group {
|
||||
}
|
||||
|
||||
if (this.lines.length === 4) {
|
||||
this.#drawHelpLineInRect(chon)
|
||||
} else if (this.lines.length === 6) {
|
||||
this.drawHelpLineInRect(chon)
|
||||
} else if (this.lines.length === 6 || this.lines.length === 8) {
|
||||
// TODO : 6각형
|
||||
this.#drawHelpLineInHexagon(chon)
|
||||
} else if (this.lines.length === 8) {
|
||||
drawHelpLineInHexagon2(this, chon)
|
||||
} /* else if (this.lines.length === 8) {
|
||||
// TODO : 8각형
|
||||
this.#drawHelpLineInOctagon(chon)
|
||||
}
|
||||
this.drawHelpLineInOctagon(chon)
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
@ -369,7 +379,7 @@ export default class QPolygon extends fabric.Group {
|
||||
return this.shape
|
||||
}
|
||||
|
||||
#drawHelpLineInRect(chon) {
|
||||
drawHelpLineInRect(chon) {
|
||||
let type = 1
|
||||
let smallestLength = Infinity
|
||||
let maxLength = 0
|
||||
@ -514,24 +524,108 @@ export default class QPolygon extends fabric.Group {
|
||||
strokeWidth: 1,
|
||||
})
|
||||
|
||||
this.addWithUpdate(realLine1)
|
||||
this.addWithUpdate(realLine2)
|
||||
this.addWithUpdate(realLine3)
|
||||
this.addWithUpdate(realLine4)
|
||||
this.addWithUpdate(realLine5)
|
||||
this.addWithUpdate(realLine6)
|
||||
this.canvas.add(realLine1)
|
||||
this.canvas.add(realLine2)
|
||||
this.canvas.add(realLine3)
|
||||
this.canvas.add(realLine4)
|
||||
this.canvas.add(realLine5)
|
||||
this.canvas.add(realLine6)
|
||||
if (smallestLength !== maxLength) {
|
||||
// 정사각형이 아닌경우에만 용마루를 추가한다.
|
||||
this.canvas.add(ridge)
|
||||
}
|
||||
}
|
||||
drawHelpLineInHexagon2(chon) {
|
||||
const oneSideLines = [...this.lines].map((line) => {
|
||||
let newX1, newY1, newX2, newY2
|
||||
if (line.direction === 'top') {
|
||||
newX1 = line.x2
|
||||
newY1 = line.y2
|
||||
newX2 = line.x1
|
||||
newY2 = line.y1
|
||||
|
||||
line.x1 = newX1
|
||||
line.y1 = newY1
|
||||
line.x2 = newX2
|
||||
line.y2 = newY2
|
||||
line.direction = 'bottom'
|
||||
} else if (line.direction === 'left') {
|
||||
newX1 = line.x2
|
||||
newY1 = line.y2
|
||||
newX2 = line.x1
|
||||
newY2 = line.y1
|
||||
|
||||
line.x1 = newX1
|
||||
line.y1 = newY1
|
||||
line.x2 = newX2
|
||||
line.y2 = newY2
|
||||
line.direction = 'right'
|
||||
}
|
||||
return line
|
||||
})
|
||||
|
||||
const centerLines = []
|
||||
const helpLines = []
|
||||
const ridgeStartPoints = []
|
||||
|
||||
const horizontalLines = oneSideLines.filter((line) => line.direction === 'right')
|
||||
const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom')
|
||||
|
||||
const horizontalMaxLength = horizontalLines.reduce((max, obj) => Math.max(max, obj.length), 0)
|
||||
const verticalMaxLength = verticalLines.reduce((max, obj) => Math.max(max, obj.length), 0)
|
||||
// 모든 가로선의 중심선을 긋는다.
|
||||
horizontalLines.forEach((line, index) => {
|
||||
const nextLine = horizontalLines[(index + 1) % horizontalLines.length]
|
||||
|
||||
const startCenterX = Math.max(line.x1, nextLine.x1)
|
||||
const startCenterY = (line.y1 + nextLine.y1) / 2
|
||||
|
||||
let endCenterX = line.length >= nextLine.length ? startCenterX + line.length : startCenterX + nextLine.length
|
||||
const endCenterY = startCenterY
|
||||
|
||||
if (endCenterX > Math.max(line.x2, nextLine.x2)) {
|
||||
endCenterX = Math.max(line.x2, nextLine.x2)
|
||||
}
|
||||
|
||||
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
direction: 'horizontal',
|
||||
})
|
||||
|
||||
// this.addWithUpdate(centerLine)
|
||||
|
||||
centerLines.push(centerLine)
|
||||
})
|
||||
|
||||
// 모든 세로선의 중심선을 긋는다.
|
||||
verticalLines.forEach((line, index) => {
|
||||
const nextLine = verticalLines[(index + 1) % verticalLines.length]
|
||||
|
||||
const startCenterX = (line.x1 + nextLine.x1) / 2
|
||||
const startCenterY = Math.min(line.y1, nextLine.y1)
|
||||
|
||||
const endCenterX = startCenterX
|
||||
let endCenterY = line.length >= nextLine.length ? startCenterY + line.length : startCenterY + nextLine.length
|
||||
|
||||
if (endCenterY > Math.max(line.y2, nextLine.y2)) {
|
||||
endCenterY = Math.max(line.y2, nextLine.y2)
|
||||
}
|
||||
|
||||
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'blue',
|
||||
strokeWidth: 1,
|
||||
direction: 'vertical',
|
||||
})
|
||||
// this.addWithUpdate(centerLine)
|
||||
|
||||
centerLines.push(centerLine)
|
||||
})
|
||||
|
||||
const maxLength = horizontalMaxLength < verticalMaxLength ? horizontalMaxLength : verticalMaxLength
|
||||
|
||||
#drawHelpLineInHexagon(chon) {
|
||||
const historyLines = []
|
||||
const helpPoints = []
|
||||
const notInterSectionLines = []
|
||||
const ridge = []
|
||||
const maxLength = this.lines.reduce((max, obj) => Math.min(max, obj.length), 999999)
|
||||
this.points.forEach((point, index) => {
|
||||
const wallPoint = this.wall.points[index]
|
||||
// 두 점의 좌표
|
||||
@ -545,128 +639,296 @@ export default class QPolygon extends fabric.Group {
|
||||
// x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성
|
||||
const angle = Math.atan2(y2 - y1, x2 - x1)
|
||||
|
||||
newX2 = x1 + (maxLength + 50) * Math.cos(angle)
|
||||
newY2 = y1 + (maxLength + 50) * Math.sin(angle)
|
||||
newX2 = Math.floor(x1 + (maxLength / 2 + 50) * Math.cos(angle))
|
||||
newY2 = Math.floor(y1 + (maxLength / 2 + 50) * Math.sin(angle))
|
||||
|
||||
const line = new QLine([x1, y1, newX2, newY2], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'blue',
|
||||
stroke: 'green',
|
||||
idx: index,
|
||||
})
|
||||
historyLines.push(line)
|
||||
this.addWithUpdate(line)
|
||||
|
||||
helpLines.push(line)
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
|
||||
/**
|
||||
* 삼각 지붕
|
||||
*/
|
||||
historyLines.forEach((line, index) => {
|
||||
const prevLine = historyLines[(index - 1 + historyLines.length) % historyLines.length]
|
||||
|
||||
let intersectionPoint = calculateIntersection(line, prevLine)
|
||||
helpLines.forEach((line, index) => {
|
||||
if (line.isAlreadyInterSection) {
|
||||
return
|
||||
}
|
||||
const nextLine = helpLines[(index + 1 + helpLines.length) % helpLines.length]
|
||||
this.canvas.renderAll()
|
||||
|
||||
let intersectionPoint = calculateIntersection(line, nextLine)
|
||||
if (!intersectionPoint) {
|
||||
notInterSectionLines.push(line)
|
||||
return
|
||||
}
|
||||
|
||||
const helpLine1 = new QLine([prevLine.x1, prevLine.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
line.set({ isAlreadyInterSection: true })
|
||||
nextLine.set({ isAlreadyInterSection: true })
|
||||
|
||||
const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'red',
|
||||
stroke: 'skyblue',
|
||||
})
|
||||
|
||||
const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'red',
|
||||
stroke: 'skyblue',
|
||||
})
|
||||
notInterSectionLines.pop()
|
||||
helpPoints.push(intersectionPoint)
|
||||
|
||||
ridgeStartPoints.push(intersectionPoint)
|
||||
this.addWithUpdate(helpLine1)
|
||||
this.addWithUpdate(helpLine2)
|
||||
this.removeWithUpdate(prevLine)
|
||||
this.removeWithUpdate(nextLine)
|
||||
this.removeWithUpdate(line)
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
// 용마루
|
||||
|
||||
const ridgePoint = []
|
||||
// 안만나는 선들
|
||||
const notInterSectionLines = helpLines.filter((line) => !line.isAlreadyInterSection)
|
||||
const ridgeEndPoints = []
|
||||
const interSectionPoints = []
|
||||
|
||||
helpPoints.forEach((helpPoint, index) => {
|
||||
const closestLine = findClosestLineToPoint(helpPoint, notInterSectionLines)
|
||||
notInterSectionLines.forEach((line, index) => {
|
||||
line.line.set({ strokeWidth: (index + 1) * 5 })
|
||||
|
||||
// 가까운 선의 중심점
|
||||
const centerClosestLinePoint = {
|
||||
x: (closestLine.x1 + closestLine.x2) / 2,
|
||||
y: (closestLine.y1 + closestLine.y2) / 2,
|
||||
}
|
||||
centerLines.forEach((centerLine) => {
|
||||
const interSectionPoint = calculateIntersection2(line, centerLine)
|
||||
|
||||
const direction = getDirectionByPoint(helpPoint, centerClosestLinePoint)
|
||||
|
||||
let newX, newY
|
||||
|
||||
switch (direction) {
|
||||
case 'left': {
|
||||
newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1
|
||||
newY = helpPoint.y
|
||||
break
|
||||
if (!this.inPolygon(interSectionPoint) || !interSectionPoint) {
|
||||
return
|
||||
}
|
||||
case 'right': {
|
||||
newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1
|
||||
newY = helpPoint.y
|
||||
break
|
||||
}
|
||||
case 'top': {
|
||||
newX = helpPoint.x
|
||||
newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1
|
||||
break
|
||||
}
|
||||
case 'bottom': {
|
||||
newX = helpPoint.x
|
||||
newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const ridgeHelpLine = new QLine([closestLine.x1, closestLine.y1, newX, newY], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'purple',
|
||||
strokeWidth: 5,
|
||||
line.interSectionPoints.push(interSectionPoint)
|
||||
interSectionPoints.push(interSectionPoint)
|
||||
})
|
||||
|
||||
ridgePoint.push({ x: newX, y: newY })
|
||||
|
||||
const ridge = new QLine([helpPoint.x, helpPoint.y, newX, newY], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'skyblue',
|
||||
strokeWidth: 5,
|
||||
})
|
||||
|
||||
this.addWithUpdate(ridge)
|
||||
this.canvas.renderAll()
|
||||
|
||||
this.addWithUpdate(ridgeHelpLine)
|
||||
this.removeWithUpdate(closestLine)
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
|
||||
// 용마루 끼리 연결
|
||||
for (let i = 0; i < ridgePoint.length; i = i + 2) {
|
||||
const currentRidgeEndPoint = ridgePoint[i]
|
||||
const nextRidgeEndPoint = ridgePoint[(i + 1) % ridgePoint.length]
|
||||
ridgeStartPoints.forEach((point, index) => {
|
||||
let arrivalPoint
|
||||
let distance = Infinity
|
||||
let startPoint
|
||||
interSectionPoints.forEach((interSectionPoint) => {
|
||||
if (Math.abs(point.x - interSectionPoint.x) < 3 || Math.abs(point.y - interSectionPoint.y) < 3) {
|
||||
if (distanceBetweenPoints(point, interSectionPoint) < distance) {
|
||||
startPoint = point
|
||||
distance = distanceBetweenPoints(point, interSectionPoint)
|
||||
arrivalPoint = interSectionPoint
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (arrivalPoint) {
|
||||
const line = notInterSectionLines.filter((line) => line.interSectionPoints.includes(arrivalPoint))[0]
|
||||
|
||||
const ridge = new QLine([startPoint.x, startPoint.y, arrivalPoint.x, arrivalPoint.y], {
|
||||
stroke: 'black',
|
||||
fontSize: this.fontSize,
|
||||
})
|
||||
|
||||
const helpLine = new QLine([line.x1, line.y1, arrivalPoint.x, arrivalPoint.y], {
|
||||
stroke: 'red',
|
||||
fontSize: this.fontSize,
|
||||
})
|
||||
|
||||
ridgeEndPoints.push(arrivalPoint)
|
||||
this.addWithUpdate(ridge)
|
||||
this.addWithUpdate(helpLine)
|
||||
this.removeWithUpdate(line)
|
||||
this.canvas.renderAll()
|
||||
}
|
||||
})
|
||||
|
||||
ridgeEndPoints.forEach((point, index) => {
|
||||
const currentRidgeEndPoint = ridgeEndPoints[index]
|
||||
const nextRidgeEndPoint = ridgeEndPoints[(index + 1) % ridgeEndPoints.length]
|
||||
const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'green',
|
||||
strokeWidth: 5,
|
||||
})
|
||||
|
||||
this.addWithUpdate(ridgeConnectLine)
|
||||
this.canvas.renderAll()
|
||||
}
|
||||
})
|
||||
}
|
||||
drawHelpLineInHexagon(chon) {
|
||||
const historyLines = []
|
||||
const helpPoints = []
|
||||
const notInterSectionLines = []
|
||||
const ridge = []
|
||||
const maxLength = this.lines.reduce((max, obj) => Math.max(max, obj.length), 0)
|
||||
this.points.forEach((point, index) => {
|
||||
const wallPoint = this.wall.points[index]
|
||||
// 두 점의 좌표
|
||||
const x1 = point.x
|
||||
const y1 = point.y
|
||||
const x2 = wallPoint.x
|
||||
const y2 = wallPoint.y
|
||||
const historyLines = []
|
||||
const helpPoints = []
|
||||
const notInterSectionLines = []
|
||||
const ridge = []
|
||||
const maxLength = this.lines.reduce((max, obj) => Math.max(max, obj.length), 0)
|
||||
this.points.forEach((point, index) => {
|
||||
const wallPoint = this.wall.points[index]
|
||||
// 두 점의 좌표
|
||||
const x1 = point.x
|
||||
const y1 = point.y
|
||||
const x2 = wallPoint.x
|
||||
const y2 = wallPoint.y
|
||||
|
||||
this.canvas.renderAll()
|
||||
let newX2, newY2
|
||||
|
||||
// x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성
|
||||
const angle = Math.atan2(y2 - y1, x2 - x1)
|
||||
|
||||
newX2 = x1 + (maxLength / 2) * Math.cos(angle)
|
||||
newY2 = y1 + (maxLength / 2) * Math.sin(angle)
|
||||
|
||||
const line = new QLine([x1, y1, newX2, newY2], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'blue',
|
||||
idx: index,
|
||||
})
|
||||
historyLines.push(line)
|
||||
this.canvas.add(line)
|
||||
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
|
||||
/**
|
||||
* 삼각 지붕
|
||||
*/
|
||||
historyLines.forEach((line, index) => {
|
||||
const prevLine = historyLines[(index - 1 + historyLines.length) % historyLines.length]
|
||||
|
||||
let intersectionPoint = calculateIntersection(line, prevLine)
|
||||
|
||||
if (!intersectionPoint) {
|
||||
notInterSectionLines.push(line)
|
||||
return
|
||||
}
|
||||
|
||||
const helpLine1 = new QLine([prevLine.x1, prevLine.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'red',
|
||||
})
|
||||
|
||||
const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'red',
|
||||
})
|
||||
notInterSectionLines.pop()
|
||||
helpPoints.push(intersectionPoint)
|
||||
|
||||
this.canvas.add(helpLine1)
|
||||
this.canvas.add(helpLine2)
|
||||
this.canvas.remove(prevLine)
|
||||
this.canvas.remove(line)
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
// 용마루
|
||||
|
||||
const ridgePoint = []
|
||||
|
||||
helpPoints.forEach((helpPoint, index) => {
|
||||
const closestLine = findClosestLineToPoint(helpPoint, notInterSectionLines)
|
||||
|
||||
// 가까운 선의 중심점
|
||||
const centerClosestLinePoint = {
|
||||
x: (closestLine.x1 + closestLine.x2) / 2,
|
||||
y: (closestLine.y1 + closestLine.y2) / 2,
|
||||
}
|
||||
|
||||
const direction = getDirectionByPoint(helpPoint, centerClosestLinePoint)
|
||||
|
||||
let newX, newY
|
||||
|
||||
switch (direction) {
|
||||
case 'left': {
|
||||
newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1
|
||||
newY = helpPoint.y
|
||||
break
|
||||
}
|
||||
case 'right': {
|
||||
newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1
|
||||
newY = helpPoint.y
|
||||
break
|
||||
}
|
||||
case 'top': {
|
||||
newX = helpPoint.x
|
||||
newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1
|
||||
break
|
||||
}
|
||||
case 'bottom': {
|
||||
newX = helpPoint.x
|
||||
newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
const ridgeHelpLine = new QLine([closestLine.x1, closestLine.y1, newX, newY], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'purple',
|
||||
strokeWidth: 5,
|
||||
})
|
||||
|
||||
ridgePoint.push({ x: newX, y: newY })
|
||||
|
||||
const ridge = new QLine([helpPoint.x, helpPoint.y, newX, newY], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'skyblue',
|
||||
strokeWidth: 5,
|
||||
})
|
||||
|
||||
this.canvas.add(ridge)
|
||||
this.canvas.renderAll()
|
||||
|
||||
this.canvas.add(ridgeHelpLine)
|
||||
this.canvas.remove(closestLine)
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
|
||||
// 용마루 끼리 연결
|
||||
for (let i = 0; i < ridgePoint.length; i = i + 2) {
|
||||
const currentRidgeEndPoint = ridgePoint[i]
|
||||
const nextRidgeEndPoint = ridgePoint[(i + 1) % ridgePoint.length]
|
||||
const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], {
|
||||
fontSize: this.fontSize,
|
||||
stroke: 'green',
|
||||
strokeWidth: 5,
|
||||
})
|
||||
this.canvas.add(ridgeConnectLine)
|
||||
this.canvas.renderAll()
|
||||
}
|
||||
|
||||
this.canvas.renderAll()
|
||||
})
|
||||
}
|
||||
|
||||
#drawHelpLineInOctagon(chon) {}
|
||||
drawHelpLineInOctagon(chon) {}
|
||||
|
||||
getObject() {
|
||||
return this
|
||||
}
|
||||
sou
|
||||
|
||||
toObject(propertiesToInclude) {
|
||||
return fabric.util.object.extend(this.callSuper('toObject'), {
|
||||
points: this.points,
|
||||
fontSize: this.fontSize,
|
||||
name: this.name,
|
||||
shape: this.shape,
|
||||
texts: this.texts,
|
||||
lines: this.lines,
|
||||
wall: this.wall,
|
||||
initPoints: this.initPoints,
|
||||
initOption: this.initOption,
|
||||
objects: this.getObjects().map((obj) => obj.toObject(propertiesToInclude)),
|
||||
})
|
||||
}
|
||||
|
||||
_set(key, value) {
|
||||
this.callSuper('_set', key, value)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { fabric } from 'fabric'
|
||||
import {
|
||||
actionHandler,
|
||||
anchorWrapper,
|
||||
polygonPositionHandler,
|
||||
} from '@/util/canvas-util'
|
||||
import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util'
|
||||
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
|
||||
@ -31,17 +27,6 @@ export function useCanvas(id) {
|
||||
selection: false,
|
||||
})
|
||||
|
||||
// settings for all canvas in the app
|
||||
fabric.Object.prototype.transparentCorners = false
|
||||
fabric.Object.prototype.cornerColor = '#2BEBC8'
|
||||
fabric.Object.prototype.cornerStyle = 'rect'
|
||||
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()
|
||||
@ -57,24 +42,14 @@ export function useCanvas(id) {
|
||||
useEffect(() => {
|
||||
canvas
|
||||
?.getObjects()
|
||||
.filter(
|
||||
(obj) =>
|
||||
obj.type === 'textbox' ||
|
||||
obj.type === 'text' ||
|
||||
obj.type === 'i-text',
|
||||
)
|
||||
.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',
|
||||
)
|
||||
.filter((obj) => obj.type === 'QLine' || obj.type === 'QPolygon' || obj.type === 'QRect')
|
||||
.forEach((obj) => {
|
||||
obj.setFontSize(fontSize)
|
||||
})
|
||||
@ -121,26 +96,43 @@ export function useCanvas(id) {
|
||||
*/
|
||||
const removeMouseLines = () => {
|
||||
if (canvas?._objects.length > 0) {
|
||||
const mouseLines = canvas?._objects.filter(
|
||||
(obj) => obj.name === 'mouseLine',
|
||||
)
|
||||
const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine')
|
||||
mouseLines.forEach((item) => canvas?.remove(item))
|
||||
}
|
||||
canvas?.renderAll()
|
||||
}
|
||||
|
||||
/**
|
||||
* 눈금 그리기
|
||||
*/
|
||||
const initialize = () => {
|
||||
canvas?.clear()
|
||||
// settings for all canvas in the app
|
||||
fabric.Object.prototype.transparentCorners = false
|
||||
fabric.Object.prototype.cornerColor = '#2BEBC8'
|
||||
fabric.Object.prototype.cornerStyle = 'rect'
|
||||
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
|
||||
fabric.Object.prototype.cornerSize = 6
|
||||
|
||||
// 기존 이벤트가 있을 경우 제거한다.
|
||||
// removeEventOnCanvas()
|
||||
QPolygon.prototype.canvas = canvas
|
||||
QLine.prototype.canvas = canvas
|
||||
QRect.prototype.canvas = canvas
|
||||
|
||||
// 작업 후에 event를 추가해준다.
|
||||
fabric.QLine = fabric.util.createClass(fabric.Group, {})
|
||||
fabric.QPolygon = fabric.util.createClass(fabric.Group, {})
|
||||
|
||||
// addEventOnCanvas()
|
||||
// fromObject 메서드를 QLine 클래스에 직접 추가
|
||||
fabric.QLine.fromObject = function (object, callback) {
|
||||
const { initOption, initPoints, initLengthTxt } = object
|
||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
||||
return callback(new QLine(initPoints, initOption, initLengthTxt))
|
||||
})
|
||||
}
|
||||
|
||||
// fromObject 메서드를 QLine 클래스에 직접 추가
|
||||
fabric.QPolygon.fromObject = function (object, callback) {
|
||||
const { initOption, initPoints, initLengthTxt } = object
|
||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
||||
return callback(new QPolygon(initPoints, initOption, initLengthTxt))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,26 +168,20 @@ export function useCanvas(id) {
|
||||
}
|
||||
|
||||
// 가로선을 그립니다.
|
||||
const horizontalLine = new fabric.Line(
|
||||
[0, pointer.y, canvasSize.horizontal, pointer.y],
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
},
|
||||
)
|
||||
const horizontalLine = new fabric.Line([0, pointer.y, canvasSize.horizontal, pointer.y], {
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
})
|
||||
|
||||
// 세로선을 그립니다.
|
||||
const verticalLine = new fabric.Line(
|
||||
[pointer.x, 0, pointer.x, canvasSize.vertical],
|
||||
{
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
},
|
||||
)
|
||||
const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, canvasSize.vertical], {
|
||||
stroke: 'black',
|
||||
strokeWidth: 1,
|
||||
selectable: false,
|
||||
name: 'mouseLine',
|
||||
})
|
||||
|
||||
// 선들을 캔버스에 추가합니다.
|
||||
canvas?.add(horizontalLine, verticalLine)
|
||||
@ -325,7 +311,6 @@ export function useCanvas(id) {
|
||||
}
|
||||
const jsonStr = JSON.stringify(canvas)
|
||||
localStorage.setItem('canvas', jsonStr)
|
||||
handleClear()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -479,10 +464,7 @@ export function useCanvas(id) {
|
||||
poly.controls = poly.points.reduce(function (acc, point, index) {
|
||||
acc['p' + index] = new fabric.Control({
|
||||
positionHandler: polygonPositionHandler,
|
||||
actionHandler: anchorWrapper(
|
||||
index > 0 ? index - 1 : lastControl,
|
||||
actionHandler,
|
||||
),
|
||||
actionHandler: anchorWrapper(index > 0 ? index - 1 : lastControl, actionHandler),
|
||||
actionName: 'modifyPolygon',
|
||||
pointIndex: index,
|
||||
})
|
||||
@ -571,6 +553,54 @@ export function useCanvas(id) {
|
||||
})
|
||||
}
|
||||
|
||||
const addCanvas = () => {
|
||||
// const canvasState = canvas
|
||||
|
||||
const objs = canvas
|
||||
|
||||
console.log(objs)
|
||||
const str = JSON.stringify(objs)
|
||||
|
||||
canvas?.clear()
|
||||
|
||||
console.log(str)
|
||||
console.log(JSON.parse(str))
|
||||
|
||||
// 역직렬화하여 캔버스에 객체를 다시 추가합니다.
|
||||
setTimeout(() => {
|
||||
canvas?.loadFromJSON(
|
||||
JSON.parse(str),
|
||||
function () {
|
||||
// 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
|
||||
canvas?.renderAll() // 캔버스를 다시 그립니다.
|
||||
console.log('Objects are reloaded and rendered on canvas.')
|
||||
},
|
||||
function (o, object) {
|
||||
// 각 객체가 로드될 때마다 호출됩니다.
|
||||
console.log('Object loaded: ', o, object)
|
||||
|
||||
canvas?.add(object)
|
||||
canvas?.renderAll()
|
||||
},
|
||||
)
|
||||
}, 1000)
|
||||
|
||||
/*canvas?.loadFromJSON(JSON.parse(str), () => {
|
||||
console.log('load done')
|
||||
})*/
|
||||
|
||||
/*const stateArr = canvasState.map((state) => state.getObject().getObjects())
|
||||
|
||||
const newCanvasList = [...canvasList, JSON.stringify(stateArr)]
|
||||
|
||||
setCanvasList(newCanvasList)*/
|
||||
}
|
||||
|
||||
const changeCanvas = (idx) => {
|
||||
canvas?.clear()
|
||||
const canvasState = JSON.parse(canvasList[idx])
|
||||
}
|
||||
|
||||
return {
|
||||
canvas,
|
||||
addShape,
|
||||
@ -585,5 +615,7 @@ export function useCanvas(id) {
|
||||
saveImage,
|
||||
handleFlip,
|
||||
setCanvasBackgroundWithDots,
|
||||
addCanvas,
|
||||
changeCanvas,
|
||||
}
|
||||
}
|
||||
|
||||
1324
src/hooks/useMode.js
1324
src/hooks/useMode.js
File diff suppressed because it is too large
Load Diff
38
src/lib/canvas.js
Normal file
38
src/lib/canvas.js
Normal file
@ -0,0 +1,38 @@
|
||||
'use server'
|
||||
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
export const getTests = () => {
|
||||
return prisma.test.findMany()
|
||||
}
|
||||
|
||||
export const insertTest = async (param) => {
|
||||
return prisma.test.create({
|
||||
data: {
|
||||
content: param,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const getCanvasStateAll = () => {
|
||||
return prisma.canvas.findMany()
|
||||
}
|
||||
|
||||
export const getCanvasState = () => {
|
||||
return prisma.canvas.findFirst({
|
||||
where: {
|
||||
loginId: 'test',
|
||||
},
|
||||
orderBy: {
|
||||
id: 'desc',
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export const insertCanvasState = (param) => {
|
||||
return prisma.canvas.create({
|
||||
data: param,
|
||||
})
|
||||
}
|
||||
14
src/lib/prisma.js
Normal file
14
src/lib/prisma.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
let prisma
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
prisma = new PrismaClient()
|
||||
} else {
|
||||
if (!global.prisma) {
|
||||
global.prisma = new PrismaClient()
|
||||
}
|
||||
prisma = global.prisma
|
||||
}
|
||||
|
||||
export default prisma
|
||||
@ -13,8 +13,8 @@ export const fontSizeState = atom({
|
||||
export const canvasSizeState = atom({
|
||||
key: 'canvasSize',
|
||||
default: {
|
||||
vertical: 1000,
|
||||
horizontal: 1000,
|
||||
vertical: 1500,
|
||||
horizontal: 1500,
|
||||
},
|
||||
})
|
||||
|
||||
@ -35,3 +35,9 @@ export const wallState = atom({
|
||||
default: {},
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
export const roofPolygonPatternArrayState = atom({
|
||||
key: 'roofPolygonPattern',
|
||||
default: {}, //object ex) big, mid, sht = {point : [{x1, y1}, {x2, y1}], direction : left or right or top or bottom}
|
||||
dangerouslyAllowMutability: true,
|
||||
})
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
import { intersect } from 'mathjs'
|
||||
|
||||
/**
|
||||
* Collection of function to use on canvas
|
||||
*/
|
||||
@ -9,18 +11,14 @@ export function polygonPositionHandler(dim, finalMatrix, fabricObject) {
|
||||
let y = fabricObject.points[this.pointIndex].y - fabricObject.pathOffset.y
|
||||
return fabric.util.transformPoint(
|
||||
{ x, y },
|
||||
fabric.util.multiplyTransformMatrices(
|
||||
fabricObject.canvas.viewportTransform,
|
||||
fabricObject.calcTransformMatrix(),
|
||||
),
|
||||
fabric.util.multiplyTransformMatrices(fabricObject.canvas.viewportTransform, fabricObject.calcTransformMatrix()),
|
||||
)
|
||||
}
|
||||
|
||||
function getObjectSizeWithStroke(object) {
|
||||
let stroke = new fabric.Point(
|
||||
object.strokeUniform ? 1 / object.scaleX : 1,
|
||||
object.strokeUniform ? 1 / object.scaleY : 1,
|
||||
).multiply(object.strokeWidth)
|
||||
let stroke = new fabric.Point(object.strokeUniform ? 1 / object.scaleX : 1, object.strokeUniform ? 1 / object.scaleY : 1).multiply(
|
||||
object.strokeWidth,
|
||||
)
|
||||
return new fabric.Point(object.width + stroke.x, object.height + stroke.y)
|
||||
}
|
||||
|
||||
@ -28,20 +26,12 @@ function getObjectSizeWithStroke(object) {
|
||||
export function actionHandler(eventData, transform, x, y) {
|
||||
let polygon = transform.target,
|
||||
currentControl = polygon.controls[polygon.__corner],
|
||||
mouseLocalPosition = polygon.toLocalPoint(
|
||||
new fabric.Point(x, y),
|
||||
'center',
|
||||
'center',
|
||||
),
|
||||
mouseLocalPosition = polygon.toLocalPoint(new fabric.Point(x, y), 'center', 'center'),
|
||||
polygonBaseSize = getObjectSizeWithStroke(polygon),
|
||||
size = polygon._getTransformedDimensions(0, 0)
|
||||
polygon.points[currentControl.pointIndex] = {
|
||||
x:
|
||||
(mouseLocalPosition.x * polygonBaseSize.x) / size.x +
|
||||
polygon.pathOffset.x,
|
||||
y:
|
||||
(mouseLocalPosition.y * polygonBaseSize.y) / size.y +
|
||||
polygon.pathOffset.y,
|
||||
x: (mouseLocalPosition.x * polygonBaseSize.x) / size.x + polygon.pathOffset.x,
|
||||
y: (mouseLocalPosition.y * polygonBaseSize.y) / size.y + polygon.pathOffset.y,
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -50,8 +40,7 @@ export function actionHandler(eventData, transform, x, y) {
|
||||
export function anchorWrapper(anchorIndex, fn) {
|
||||
return function (eventData, transform, x, y) {
|
||||
let fabricObject = transform.target
|
||||
let originX =
|
||||
fabricObject?.points[anchorIndex].x - fabricObject.pathOffset.x
|
||||
let originX = fabricObject?.points[anchorIndex].x - fabricObject.pathOffset.x
|
||||
let originY = fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y
|
||||
let absolutePoint = fabric.util.transformPoint(
|
||||
{
|
||||
@ -63,12 +52,8 @@ export function anchorWrapper(anchorIndex, fn) {
|
||||
let actionPerformed = fn(eventData, transform, x, y)
|
||||
let newDim = fabricObject._setPositionDimensions({})
|
||||
let polygonBaseSize = getObjectSizeWithStroke(fabricObject)
|
||||
let newX =
|
||||
(fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) /
|
||||
polygonBaseSize.x
|
||||
let newY =
|
||||
(fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) /
|
||||
polygonBaseSize.y
|
||||
let newX = (fabricObject.points[anchorIndex].x - fabricObject.pathOffset.x) / polygonBaseSize.x
|
||||
let newY = (fabricObject.points[anchorIndex].y - fabricObject.pathOffset.y) / polygonBaseSize.y
|
||||
fabricObject.setPositionByOrigin(absolutePoint, newX + 0.5, newY + 0.5)
|
||||
return actionPerformed
|
||||
}
|
||||
@ -104,9 +89,7 @@ export function addDistanceTextToPolygon(polygon) {
|
||||
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 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), {
|
||||
// 소수 둘째자리까지 표시
|
||||
@ -160,10 +143,7 @@ export const getStartIndex = (lines) => {
|
||||
let smallestY1 = lines[0].y1
|
||||
|
||||
for (let i = 1; i < lines.length; i++) {
|
||||
if (
|
||||
lines[i].x1 < smallestX1 ||
|
||||
(lines[i].x1 === smallestX1 && lines[i].y1 < smallestY1)
|
||||
) {
|
||||
if (lines[i].x1 < smallestX1 || (lines[i].x1 === smallestX1 && lines[i].y1 < smallestY1)) {
|
||||
smallestIndex = i
|
||||
smallestX1 = lines[i].x1
|
||||
smallestY1 = lines[i].y1
|
||||
@ -184,10 +164,7 @@ export const getStartIndexPoint = (points) => {
|
||||
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)
|
||||
) {
|
||||
if (points[i].x < smallestX1 || (points[i].x === smallestX1 && points[i].y < smallestY1)) {
|
||||
smallestIndex = i
|
||||
smallestX1 = points[i].x
|
||||
smallestY1 = points[i].y
|
||||
@ -316,50 +293,128 @@ export const getDirectionByPoint = (a, b) => {
|
||||
}
|
||||
|
||||
/**
|
||||
* line을 두개를 이용해서 교차점을 찾는 함수
|
||||
* @param line1
|
||||
* @param line2
|
||||
* @returns {{x: number, y: number}|null}
|
||||
* 두 선분의 교차점을 찾는 함수입니다. 이 함수는 두 선분이 실제로 교차하는 지점 내에서 교차하는지 확인합니다.
|
||||
* @param {Object} line1 첫 번째 선분, {x1, y1, x2, y2} 형태의 객체
|
||||
* @param {Object} line2 두 번째 선분, {x1, y1, x2, y2} 형태의 객체
|
||||
* @returns {{x: number, y: number}|null} 교차점의 좌표를 반환하거나, 교차점이 없으면 null을 반환합니다.
|
||||
*/
|
||||
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 { x1: x1_1, y1: y1_1, x2: x2_1, y2: y2_1 } = line1
|
||||
const { x1: x1_2, y1: y1_2, x2: x2_2, y2: y2_2 } = line2
|
||||
|
||||
const denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)
|
||||
if (denom === 0) return null // 선분이 평행하거나 일치
|
||||
const denominator = (x1_1 - x2_1) * (y1_2 - y2_2) - (y1_1 - y2_1) * (x1_2 - x2_2)
|
||||
if (denominator === 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
|
||||
const t = ((x1_1 - x1_2) * (y1_2 - y2_2) - (y1_1 - y1_2) * (x1_2 - x2_2)) / denominator
|
||||
const u = -((x1_1 - x2_1) * (y1_1 - y1_2) - (y1_1 - y2_1) * (x1_1 - x1_2)) / denominator
|
||||
|
||||
// 교차점이 두 선분의 x 좌표 범위 내에 있는지 확인
|
||||
if (
|
||||
intersectX < Math.min(x1, x2) ||
|
||||
intersectX > Math.max(x1, x2) ||
|
||||
intersectX < Math.min(x3, x4) ||
|
||||
intersectX > Math.max(x3, x4)
|
||||
) {
|
||||
return null // 교차점이 선분 범위 밖에 있음
|
||||
// t와 u가 모두 0과 1 사이에 있을 때, 선분 내에서 교차
|
||||
if (t >= 0 && t <= 1 && u >= 0 && u <= 1) {
|
||||
const intersectionX = x1_1 + t * (x2_1 - x1_1)
|
||||
const intersectionY = y1_1 + t * (y2_1 - y1_1)
|
||||
|
||||
// Determine the min and max for line1 and line2 for both x and y
|
||||
const line1MinX = Math.min(line1.x1, line1.x2)
|
||||
const line1MaxX = Math.max(line1.x1, line1.x2)
|
||||
const line2MinX = Math.min(line2.x1, line2.x2)
|
||||
const line2MaxX = Math.max(line2.x1, line2.x2)
|
||||
|
||||
const line1MinY = Math.min(line1.y1, line1.y2)
|
||||
const line1MaxY = Math.max(line1.y1, line1.y2)
|
||||
const line2MinY = Math.min(line2.y1, line2.y2)
|
||||
const line2MaxY = Math.max(line2.y1, line2.y2)
|
||||
|
||||
// 교차점이 선분의 범위 내에 있는지 확인
|
||||
if (
|
||||
intersectionX >= line1MinX &&
|
||||
intersectionX <= line1MaxX &&
|
||||
intersectionX >= line2MinX &&
|
||||
intersectionX <= line2MaxX &&
|
||||
intersectionY >= line1MinY &&
|
||||
intersectionY <= line1MaxY &&
|
||||
intersectionY >= line2MinY &&
|
||||
intersectionY <= line2MaxY
|
||||
) {
|
||||
return { x: Math.round(intersectionX), y: Math.round(intersectionY) }
|
||||
}
|
||||
}
|
||||
|
||||
return { x: intersectX, y: intersectY }
|
||||
return null // 교차점이 선분의 범위 내에 없음
|
||||
}
|
||||
|
||||
function findOrthogonalPoint(x1, y1, x2, y2, x3, y3, x4, y4) {
|
||||
export const findIntersection1 = (line1, line2) => {
|
||||
const { x1, y1, x2, y2 } = line1 // 첫 번째 선의 두 점
|
||||
|
||||
const x3 = line2.x1
|
||||
const y3 = line2.y1
|
||||
const x4 = line2.x2
|
||||
const y4 = line2.y2
|
||||
|
||||
// 선의 방정식의 계수 계산
|
||||
const A1 = y2 - y1
|
||||
const B1 = x1 - x2
|
||||
const C1 = A1 * x1 + B1 * y1
|
||||
|
||||
const A2 = y4 - y3
|
||||
const B2 = x3 - x4
|
||||
const C2 = A2 * x3 + B2 * y3
|
||||
|
||||
const determinant = A1 * B2 - A2 * B1
|
||||
|
||||
if (determinant === 0) {
|
||||
// 두 선이 평행하거나 일직선일 경우
|
||||
return null
|
||||
}
|
||||
|
||||
const x = (B1 * C2 - B2 * C1) / determinant
|
||||
const y = (A1 * C2 - A2 * C1) / determinant
|
||||
|
||||
return { x, y }
|
||||
}
|
||||
|
||||
export const calculateIntersection2 = (line1, line2) => {
|
||||
const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2])
|
||||
|
||||
if (!result) {
|
||||
return null
|
||||
}
|
||||
|
||||
// Determine the min and max for line1 and line2 for both x and y
|
||||
const line1MinX = Math.min(line1.x1, line1.x2)
|
||||
const line1MaxX = Math.max(line1.x1, line1.x2)
|
||||
const line2MinX = Math.min(line2.x1, line2.x2)
|
||||
const line2MaxX = Math.max(line2.x1, line2.x2)
|
||||
|
||||
const line1MinY = Math.min(line1.y1, line1.y2)
|
||||
const line1MaxY = Math.max(line1.y1, line1.y2)
|
||||
const line2MinY = Math.min(line2.y1, line2.y2)
|
||||
const line2MaxY = Math.max(line2.y1, line2.y2)
|
||||
|
||||
// Check if the intersection X and Y are within the range of both lines
|
||||
if (
|
||||
result[0] >= line1MinX &&
|
||||
result[0] <= line1MaxX &&
|
||||
result[0] >= line2MinX &&
|
||||
result[0] <= line2MaxX &&
|
||||
result[1] >= line1MinY &&
|
||||
result[1] <= line1MaxY &&
|
||||
result[1] >= line2MinY &&
|
||||
result[1] <= line2MaxY
|
||||
) {
|
||||
return { x: Math.round(result[0]), y: Math.round(result[1]) }
|
||||
} else {
|
||||
return null // Intersection is out of range
|
||||
}
|
||||
}
|
||||
|
||||
export function findOrthogonalPoint(line1, line2) {
|
||||
// Calculate the intersection point of two lines
|
||||
const intersectionX =
|
||||
((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
|
||||
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
|
||||
((line1.x1 * line2.y1 - line1.y1 * line2.x1) * (line2.x2 - line2.x1) - (line1.x1 - line1.x2) * (line2.x2 * line2.y2 - line2.y1 * line2.x1)) /
|
||||
((line1.x1 - line1.x2) * (line2.y1 - line2.y2) - (line1.y1 - line1.y2) * (line2.x2 - line2.x1))
|
||||
const intersectionY =
|
||||
((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
|
||||
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
|
||||
((line1.x1 * line2.y1 - line1.y1 * line2.x1) * (line2.y2 - line2.y1) - (line1.y1 - line1.y2) * (line2.x2 * line2.y2 - line2.y1 * line2.x1)) /
|
||||
((line1.x1 - line1.x2) * (line2.y1 - line2.y2) - (line1.y1 - line1.y2) * (line2.x2 - line2.x1))
|
||||
|
||||
return { x: intersectionX, y: intersectionY }
|
||||
}
|
||||
@ -371,7 +426,6 @@ function findOrthogonalPoint(x1, y1, x2, y2, x3, y3, x4, y4) {
|
||||
export const sortedPoints = (points) => {
|
||||
const copyPoints = [...points]
|
||||
//points를 x,y좌표를 기준으로 정렬합니다.
|
||||
|
||||
copyPoints.sort((a, b) => {
|
||||
if (a.x === b.x) {
|
||||
return a.y - b.y
|
||||
@ -387,7 +441,6 @@ export const sortedPoints = (points) => {
|
||||
let index = 1
|
||||
let currentPoint = { ...copyPoints[0] }
|
||||
copyPoints.splice(0, 1)
|
||||
|
||||
while (index < points.length) {
|
||||
if (index === points.length - 1) {
|
||||
resultPoints.push(copyPoints[0])
|
||||
@ -397,14 +450,18 @@ export const sortedPoints = (points) => {
|
||||
// 짝수번째는 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)
|
||||
let temp = copyPoints.filter((point) => point.y === currentPoint.y)
|
||||
if (temp.length === 0) {
|
||||
// temp가 비어있을 경우 copyPoints에서 가장 가까운 점을 찾는다.
|
||||
temp = Array.of(findClosestPointByY(currentPoint, copyPoints))
|
||||
}
|
||||
// temp중 x값이 가장 가까운 값
|
||||
|
||||
const min = temp.reduce((prev, current) => (Math.abs(current.x - currentPoint.x) <= Math.abs(prev.x - currentPoint.x) ? current : prev))
|
||||
|
||||
resultPoints.push(min)
|
||||
currentPoint = min
|
||||
copyPoints.splice(copyPoints.indexOf(min), 1)
|
||||
index++
|
||||
break
|
||||
}
|
||||
@ -412,21 +469,23 @@ export const sortedPoints = (points) => {
|
||||
// 홀수번째는 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,
|
||||
)
|
||||
let temp = copyPoints.filter((point) => point.x === currentPoint.x)
|
||||
if (temp.length === 0) {
|
||||
// temp가 비어있을 경우 copyPoints에서 가장 가까운 점을 찾는다.
|
||||
|
||||
resultPoints.push(max)
|
||||
currentPoint = max
|
||||
copyPoints.splice(copyPoints.indexOf(max), 1)
|
||||
temp = Array.of(findClosestPointByX(currentPoint, copyPoints))
|
||||
}
|
||||
// temp중 y값이 가장 가까운 값
|
||||
const min = temp.reduce((prev, current) => (Math.abs(current.y - currentPoint.y) <= Math.abs(prev.y - currentPoint.y) ? current : prev))
|
||||
|
||||
resultPoints.push(min)
|
||||
currentPoint = min
|
||||
copyPoints.splice(copyPoints.indexOf(min), 1)
|
||||
index++
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resultPoints
|
||||
}
|
||||
|
||||
@ -467,6 +526,81 @@ export function findClosestLineToPoint(point, lines) {
|
||||
return closestLine
|
||||
}
|
||||
|
||||
/**
|
||||
* x값이 가장 가까운 점
|
||||
* @param targetPoint
|
||||
* @param points
|
||||
* @returns {*|null}
|
||||
*/
|
||||
function findClosestPointByX(targetPoint, points) {
|
||||
if (points.length === 0) {
|
||||
return null // Return null if the points array is empty
|
||||
}
|
||||
|
||||
let closestPoint = points[0]
|
||||
let smallestDistance = Math.abs(targetPoint.x - points[0].x)
|
||||
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
const currentDistance = Math.abs(targetPoint.x - points[i].x)
|
||||
if (currentDistance < smallestDistance) {
|
||||
smallestDistance = currentDistance
|
||||
closestPoint = points[i]
|
||||
}
|
||||
}
|
||||
|
||||
return closestPoint
|
||||
}
|
||||
|
||||
/**
|
||||
* y값이 가장 가까운 점
|
||||
* @param targetPoint
|
||||
* @param points
|
||||
* @returns {*|null}
|
||||
*/
|
||||
function findClosestPointByY(targetPoint, points) {
|
||||
if (points.length === 0) {
|
||||
return null // Return null if the points array is empty
|
||||
}
|
||||
|
||||
let closestPoint = points[0]
|
||||
let smallestDistance = Math.abs(targetPoint.y - points[0].y)
|
||||
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
const currentDistance = Math.abs(targetPoint.y - points[i].y)
|
||||
if (currentDistance < smallestDistance) {
|
||||
smallestDistance = currentDistance
|
||||
closestPoint = points[i]
|
||||
}
|
||||
}
|
||||
|
||||
return closestPoint
|
||||
}
|
||||
|
||||
/**
|
||||
* 주어진 점에서 points 배열 중 가장 가까운 점을 찾는 함수입니다.
|
||||
* @param {Object} targetPoint - { x: number, y: number } 형태의 대상 점 객체
|
||||
* @param {Array} points - { x: number, y: number } 형태의 점 객체들의 배열
|
||||
* @returns {Object} targetPoint에 가장 가까운 점 객체
|
||||
*/
|
||||
export function findClosestPoint(targetPoint, points) {
|
||||
if (points.length === 0) {
|
||||
return null // points 배열이 비어있으면 null 반환
|
||||
}
|
||||
|
||||
let closestPoint = points[0]
|
||||
let smallestDistance = calculateDistancePoint(targetPoint, closestPoint)
|
||||
|
||||
for (let i = 1; i < points.length; i++) {
|
||||
const currentDistance = calculateDistancePoint(targetPoint, points[i])
|
||||
if (currentDistance < smallestDistance) {
|
||||
smallestDistance = currentDistance
|
||||
closestPoint = points[i]
|
||||
}
|
||||
}
|
||||
|
||||
return closestPoint
|
||||
}
|
||||
|
||||
/**
|
||||
* 점과 직선사이의 최단 거리
|
||||
* @param point
|
||||
@ -481,9 +615,37 @@ export function calculateDistance(point, line) {
|
||||
const x0 = point.x
|
||||
const y0 = point.y
|
||||
|
||||
const numerator = Math.abs(
|
||||
(y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1,
|
||||
)
|
||||
const numerator = Math.abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1)
|
||||
const denominator = Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2))
|
||||
return numerator / denominator
|
||||
}
|
||||
|
||||
/**
|
||||
* 두 점 사이의 거리를 계산하는 함수입니다.
|
||||
* @param {Object} point1 - 첫 번째 점 { x: number, y: number }
|
||||
* @param {Object} point2 - 두 번째 점 { x: number, y: number }
|
||||
* @returns {number} 두 점 사이의 거리
|
||||
*/
|
||||
function calculateDistancePoint(point1, point2) {
|
||||
return Math.sqrt(Math.pow(point2.x - point1.x, 2) + Math.pow(point2.y - point1.y, 2))
|
||||
}
|
||||
|
||||
/**
|
||||
* {x, y} 형태의 배열을 받아 중복된 점을 제거하는 함수
|
||||
* @param points
|
||||
* @returns {*[]}
|
||||
*/
|
||||
export function removeDuplicatePoints(points) {
|
||||
const uniquePoints = []
|
||||
const seen = new Set()
|
||||
|
||||
points.forEach((point) => {
|
||||
const identifier = `${point.x}:${point.y}`
|
||||
if (!seen.has(identifier)) {
|
||||
seen.add(identifier)
|
||||
uniquePoints.push(point)
|
||||
}
|
||||
})
|
||||
|
||||
return uniquePoints
|
||||
}
|
||||
|
||||
12
src/util/qline-utils.js
Normal file
12
src/util/qline-utils.js
Normal file
@ -0,0 +1,12 @@
|
||||
import { fabric } from 'fabric'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
|
||||
export const defineQLine = () => {
|
||||
fabric.QLine = fabric.util.createClass(fabric.Group, {})
|
||||
fabric.QLine.fromObject = function (object, callback) {
|
||||
const { initOption, initPoints, initLengthTxt } = object
|
||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
||||
return callback(new QLine(initPoints, initOption, initLengthTxt))
|
||||
})
|
||||
}
|
||||
}
|
||||
329
src/util/qpolygon-utils.js
Normal file
329
src/util/qpolygon-utils.js
Normal file
@ -0,0 +1,329 @@
|
||||
import { fabric } from 'fabric'
|
||||
import QPolygon from '@/components/fabric/QPolygon'
|
||||
import { QLine } from '@/components/fabric/QLine'
|
||||
import { calculateIntersection, calculateIntersection2, distanceBetweenPoints, findIntersection1, removeDuplicatePoints } from '@/util/canvas-util'
|
||||
|
||||
export const defineQPloygon = () => {
|
||||
fabric.QPolygon = fabric.util.createClass(fabric.Group, {})
|
||||
// fromObject 메서드를 QLine 클래스에 직접 추가
|
||||
fabric.QPolygon.fromObject = function (object, callback) {
|
||||
const { initOption, initPoints, initLengthTxt } = object
|
||||
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
|
||||
return callback(new QPolygon(initPoints, initOption, initLengthTxt))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export const drawHelpLineInHexagon2 = (polygon, chon) => {
|
||||
const oneSideLines = [...polygon.lines].map((line) => {
|
||||
let newX1, newY1, newX2, newY2
|
||||
if (line.direction === 'top') {
|
||||
newX1 = line.x2
|
||||
newY1 = line.y2
|
||||
newX2 = line.x1
|
||||
newY2 = line.y1
|
||||
|
||||
line.x1 = newX1
|
||||
line.y1 = newY1
|
||||
line.x2 = newX2
|
||||
line.y2 = newY2
|
||||
line.direction = 'bottom'
|
||||
} else if (line.direction === 'left') {
|
||||
newX1 = line.x2
|
||||
newY1 = line.y2
|
||||
newX2 = line.x1
|
||||
newY2 = line.y1
|
||||
|
||||
line.x1 = newX1
|
||||
line.y1 = newY1
|
||||
line.x2 = newX2
|
||||
line.y2 = newY2
|
||||
line.direction = 'right'
|
||||
}
|
||||
return line
|
||||
})
|
||||
|
||||
const centerLines = []
|
||||
const helpLines = []
|
||||
const ridgeStartPoints = []
|
||||
|
||||
const horizontalLines = oneSideLines.filter((line) => line.direction === 'right')
|
||||
const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom')
|
||||
// horizontalLines 를 y1 좌표 기준으로 정렬한다.
|
||||
horizontalLines.sort((a, b) => a.y1 - b.y1)
|
||||
// verticalLines 를 x1 좌표 기준으로 정렬한다.
|
||||
verticalLines.sort((a, b) => a.x1 - b.x1)
|
||||
|
||||
const maxHorizontalLineLength = horizontalLines.reduce((prev, current) => (prev.length > current.length ? prev.length : current.length))
|
||||
const maxVerticalLineLength = verticalLines.reduce((prev, current) => (prev.length > current.length ? prev.length : current.length))
|
||||
|
||||
// 모든 가로선의 중심선을 긋는다.
|
||||
horizontalLines.forEach((line, index) => {
|
||||
const nextLine = horizontalLines[(index + 1) % horizontalLines.length]
|
||||
|
||||
line.line.set({ strokeWidth: 5 })
|
||||
nextLine.line.set({ strokeWidth: 5 })
|
||||
|
||||
polygon.canvas.renderAll()
|
||||
|
||||
const startCenterX = Math.min(line.x1, nextLine.x1)
|
||||
const startCenterY = (line.y1 + nextLine.y1) / 2
|
||||
|
||||
const endCenterX = line.length >= nextLine.length ? startCenterX + line.length : startCenterX + nextLine.length
|
||||
const endCenterY = startCenterY
|
||||
|
||||
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
||||
fontSize: polygon.fontSize,
|
||||
stroke: 'red',
|
||||
strokeWidth: 1,
|
||||
direction: 'horizontal',
|
||||
})
|
||||
|
||||
/*polygon.canvas.add(centerLine)
|
||||
polygon.canvas.renderAll()*/
|
||||
|
||||
centerLines.push(centerLine)
|
||||
})
|
||||
|
||||
// 모든 세로선의 중심선을 긋는다.
|
||||
verticalLines.forEach((line, index) => {
|
||||
const nextLine = verticalLines[(index + 1) % verticalLines.length]
|
||||
|
||||
const startCenterX = (line.x1 + nextLine.x1) / 2
|
||||
const startCenterY = Math.min(line.y1, nextLine.y1)
|
||||
|
||||
const endCenterX = startCenterX
|
||||
let endCenterY = line.length >= nextLine.length ? startCenterY + line.length : startCenterY + nextLine.length
|
||||
|
||||
const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], {
|
||||
fontSize: polygon.fontSize,
|
||||
stroke: 'blue',
|
||||
strokeWidth: 1,
|
||||
direction: 'vertical',
|
||||
})
|
||||
|
||||
/*polygon.canvas.add(centerLine)
|
||||
polygon.canvas.renderAll()*/
|
||||
centerLines.push(centerLine)
|
||||
})
|
||||
|
||||
polygon.points.forEach((point, index) => {
|
||||
const wallPoint = polygon.wall.points[index]
|
||||
// 두 점의 좌표
|
||||
const x1 = point.x
|
||||
const y1 = point.y
|
||||
const x2 = wallPoint.x
|
||||
const y2 = wallPoint.y
|
||||
|
||||
let newX2, newY2
|
||||
|
||||
// x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성
|
||||
const angle = Math.atan2(y2 - y1, x2 - x1)
|
||||
|
||||
let previousIndex = index === 0 ? polygon.lines.length - 1 : index - 1
|
||||
const maxLength = Math.max(polygon.lines[index].length, polygon.lines[previousIndex].length)
|
||||
|
||||
newX2 = Math.floor(x1 + (maxLength / 2 + polygon.points.length * 10) * Math.cos(angle))
|
||||
newY2 = Math.floor(y1 + (maxLength / 2 + polygon.points.length * 10) * Math.sin(angle))
|
||||
|
||||
const line = new QLine([x1, y1, newX2, newY2], {
|
||||
fontSize: polygon.fontSize,
|
||||
stroke: 'green',
|
||||
idx: index,
|
||||
})
|
||||
line.set({ degree: fabric.util.radiansToDegrees(angle) })
|
||||
polygon.canvas.add(line)
|
||||
helpLines.push(line)
|
||||
polygon.canvas.renderAll()
|
||||
})
|
||||
|
||||
helpLines.forEach((line, index) => {
|
||||
for (let i = index + 1; i < helpLines.length; i++) {
|
||||
const nextLine = helpLines[i]
|
||||
|
||||
if (line.isAlreadyInterSection || nextLine.isAlreadyInterSection) {
|
||||
continue
|
||||
}
|
||||
|
||||
let intersectionPoint = calculateIntersection(line, nextLine)
|
||||
|
||||
if (!intersectionPoint) {
|
||||
continue
|
||||
}
|
||||
|
||||
const circle = new fabric.Circle({
|
||||
radius: 3,
|
||||
fill: 'red',
|
||||
left: intersectionPoint.x - 3,
|
||||
top: intersectionPoint.y - 3,
|
||||
})
|
||||
|
||||
polygon.canvas.add(circle)
|
||||
|
||||
line.set({ isAlreadyInterSection: true })
|
||||
nextLine.set({ isAlreadyInterSection: true })
|
||||
|
||||
const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
fontSize: polygon.fontSize,
|
||||
stroke: 'skyblue',
|
||||
})
|
||||
|
||||
const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
|
||||
fontSize: polygon.fontSize,
|
||||
stroke: 'skyblue',
|
||||
})
|
||||
|
||||
ridgeStartPoints.push(intersectionPoint)
|
||||
polygon.canvas.add(helpLine1)
|
||||
polygon.canvas.add(helpLine2)
|
||||
polygon.canvas.remove(nextLine)
|
||||
polygon.canvas.remove(line)
|
||||
polygon.canvas.renderAll()
|
||||
}
|
||||
})
|
||||
|
||||
// 안만나는 선들
|
||||
const notInterSectionLines = helpLines.filter((line) => !line.isAlreadyInterSection)
|
||||
const ridgeEndPoints = []
|
||||
let interSectionPoints = []
|
||||
|
||||
notInterSectionLines.forEach((line, index) => {
|
||||
let subCenterLines
|
||||
if (Math.abs(line.degree) < 90) {
|
||||
subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'vertical')
|
||||
} else {
|
||||
subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'horizontal')
|
||||
}
|
||||
|
||||
centerLines.forEach((centerLine) => {
|
||||
const interSectionPoint = calculateIntersection2(line, centerLine)
|
||||
|
||||
if (!interSectionPoint) {
|
||||
return
|
||||
}
|
||||
|
||||
ridgeStartPoints.forEach((point) => {
|
||||
line.interSectionPoints.push(interSectionPoint)
|
||||
interSectionPoints.push(interSectionPoint)
|
||||
|
||||
const newLine = new QLine([line.x1, line.y1, interSectionPoint.x, interSectionPoint.y], {
|
||||
stroke: 'black',
|
||||
fontSize: polygon.fontSize,
|
||||
})
|
||||
|
||||
const circle = new fabric.Circle({
|
||||
radius: 3,
|
||||
fill: 'blue',
|
||||
left: interSectionPoint.x - 3,
|
||||
top: interSectionPoint.y - 3,
|
||||
})
|
||||
polygon.canvas.add(circle)
|
||||
polygon.canvas.add(newLine)
|
||||
|
||||
polygon.canvas.remove(line)
|
||||
|
||||
line.set({ isAlreadyInterSection: true })
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
interSectionPoints = removeDuplicatePoints(interSectionPoints)
|
||||
|
||||
const startRidgePoint = ridgeStartPoints[0]
|
||||
|
||||
const endRidgePoint = ridgeStartPoints[ridgeStartPoints.length - 1]
|
||||
|
||||
let step = 0
|
||||
|
||||
while (true) {
|
||||
if (step % 2 === 0) {
|
||||
const nextPoint = interSectionPoints.find((point) => point.x === startRidgePoint.x || point.y === startRidgePoint.y)
|
||||
|
||||
if (nextPoint) {
|
||||
const ridge = new QLine([startRidgePoint.x, startRidgePoint.y, nextPoint.x, nextPoint.y], {
|
||||
stroke: 'green',
|
||||
fontSize: polygon.fontSize,
|
||||
})
|
||||
polygon.canvas.add(ridge)
|
||||
polygon.canvas.renderAll()
|
||||
}
|
||||
|
||||
console.log('nextPoint', nextPoint)
|
||||
console.log('startRidgePoint', startRidgePoint)
|
||||
} else {
|
||||
}
|
||||
|
||||
step++
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
/*ridgeStartPoints.forEach((point, index) => {
|
||||
for (let i = index + 1; i < ridgeStartPoints.length; i++) {
|
||||
const currentPoint = ridgeStartPoints[index]
|
||||
const nextPoint = ridgeStartPoints[i]
|
||||
|
||||
if (currentPoint.x === nextPoint.x || currentPoint.y === nextPoint.y) {
|
||||
const ridge = new QLine([currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y], {
|
||||
stroke: 'black',
|
||||
fontSize: polygon.fontSize,
|
||||
})
|
||||
polygon.canvas.add(ridge)
|
||||
polygon.canvas.renderAll()
|
||||
break
|
||||
}
|
||||
}
|
||||
})*/
|
||||
|
||||
/*ridgeStartPoints.forEach((point, index) => {
|
||||
let arrivalPoint
|
||||
let distance = Infinity
|
||||
let startPoint
|
||||
interSectionPoints.forEach((interSectionPoint) => {
|
||||
if (Math.abs(point.x - interSectionPoint.x) < 1 || Math.abs(point.y - interSectionPoint.y) < 1) {
|
||||
if (distanceBetweenPoints(point, interSectionPoint) < distance) {
|
||||
startPoint = point
|
||||
distance = distanceBetweenPoints(point, interSectionPoint)
|
||||
arrivalPoint = interSectionPoint
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if (arrivalPoint) {
|
||||
const line = notInterSectionLines.filter((line) => line.interSectionPoints.includes(arrivalPoint))[0]
|
||||
|
||||
const ridge = new QLine([startPoint.x, startPoint.y, arrivalPoint.x, arrivalPoint.y], {
|
||||
stroke: 'black',
|
||||
fontSize: polygon.fontSize,
|
||||
})
|
||||
|
||||
const helpLine = new QLine([line.x1, line.y1, arrivalPoint.x, arrivalPoint.y], {
|
||||
stroke: 'red',
|
||||
fontSize: polygon.fontSize,
|
||||
})
|
||||
|
||||
ridgeEndPoints.push(arrivalPoint)
|
||||
polygon.canvas.add(ridge)
|
||||
polygon.canvas.add(helpLine)
|
||||
// polygon.canvas.remove(line)
|
||||
polygon.canvas.renderAll()
|
||||
debugger
|
||||
}
|
||||
})*/
|
||||
|
||||
/*for (let i = 0; i < ridgeEndPoints.length; i = i + 2) {
|
||||
const currentRidgeEndPoint = ridgeEndPoints[i]
|
||||
const nextRidgeEndPoint = ridgeEndPoints[(i + 1) % ridgeEndPoints.length]
|
||||
const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], {
|
||||
fontSize: polygon.fontSize,
|
||||
stroke: 'green',
|
||||
})
|
||||
|
||||
polygon.canvas.add(ridgeConnectLine)
|
||||
polygon.canvas.renderAll()
|
||||
}*/
|
||||
}
|
||||
|
||||
export const drawHelpLineInHexagon = (polygon, chon) => {
|
||||
// 가장 긴라인을 기준으로 centerLine을 그린다.
|
||||
}
|
||||
118
yarn.lock
118
yarn.lock
@ -148,6 +148,13 @@
|
||||
semver "^7.3.5"
|
||||
tar "^6.1.11"
|
||||
|
||||
"@mongodb-js/saslprep@^1.1.5":
|
||||
version "1.1.8"
|
||||
resolved "https://registry.yarnpkg.com/@mongodb-js/saslprep/-/saslprep-1.1.8.tgz#d39744540be8800d17749990b0da95b4271840d1"
|
||||
integrity sha512-qKwC/M/nNNaKUBMQ0nuzm47b7ZYWQHN3pcXq4IIcoSBc2hOIrflAxJduIvvqmhoz3gR2TacTAs8vlsCVPkiEdQ==
|
||||
dependencies:
|
||||
sparse-bitfield "^3.0.3"
|
||||
|
||||
"@next/env@14.2.3":
|
||||
version "14.2.3"
|
||||
resolved "https://registry.npmjs.org/@next/env/-/env-14.2.3.tgz"
|
||||
@ -1143,6 +1150,47 @@
|
||||
resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
|
||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||
|
||||
"@prisma/client@^5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.17.0.tgz#9079947bd749689c2dabfb9ecc70a24ebefb1f43"
|
||||
integrity sha512-N2tnyKayT0Zf7mHjwEyE8iG7FwTmXDHFZ1GnNhQp0pJUObsuel4ZZ1XwfuAYkq5mRIiC/Kot0kt0tGCfLJ70Jw==
|
||||
|
||||
"@prisma/debug@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.17.0.tgz#a765105848993984535b6066f8ebc6e6ead26533"
|
||||
integrity sha512-l7+AteR3P8FXiYyo496zkuoiJ5r9jLQEdUuxIxNCN1ud8rdbH3GTxm+f+dCyaSv9l9WY+29L9czaVRXz9mULfg==
|
||||
|
||||
"@prisma/engines-version@5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053":
|
||||
version "5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053.tgz#3c7cc1ef3ebc34cbd069e5873b9982f2aabf5acd"
|
||||
integrity sha512-tUuxZZysZDcrk5oaNOdrBnnkoTtmNQPkzINFDjz7eG6vcs9AVDmA/F6K5Plsb2aQc/l5M2EnFqn3htng9FA4hg==
|
||||
|
||||
"@prisma/engines@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.17.0.tgz#74dd1aabb22675892760b3cf69a448e3aef4616b"
|
||||
integrity sha512-+r+Nf+JP210Jur+/X8SIPLtz+uW9YA4QO5IXA+KcSOBe/shT47bCcRMTYCbOESw3FFYFTwe7vU6KTWHKPiwvtg==
|
||||
dependencies:
|
||||
"@prisma/debug" "5.17.0"
|
||||
"@prisma/engines-version" "5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053"
|
||||
"@prisma/fetch-engine" "5.17.0"
|
||||
"@prisma/get-platform" "5.17.0"
|
||||
|
||||
"@prisma/fetch-engine@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.17.0.tgz#f718dc7426411d1ebeeee53e2d0d38652387f87c"
|
||||
integrity sha512-ESxiOaHuC488ilLPnrv/tM2KrPhQB5TRris/IeIV4ZvUuKeaicCl4Xj/JCQeG9IlxqOgf1cCg5h5vAzlewN91Q==
|
||||
dependencies:
|
||||
"@prisma/debug" "5.17.0"
|
||||
"@prisma/engines-version" "5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053"
|
||||
"@prisma/get-platform" "5.17.0"
|
||||
|
||||
"@prisma/get-platform@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.17.0.tgz#89fdcae2adddebbbf0e7bd0474a6c49d6023519b"
|
||||
integrity sha512-UlDgbRozCP1rfJ5Tlkf3Cnftb6srGrEQ4Nm3og+1Se2gWmCZ0hmPIi+tQikGDUVLlvOWx3Gyi9LzgRP+HTXV9w==
|
||||
dependencies:
|
||||
"@prisma/debug" "5.17.0"
|
||||
|
||||
"@react-aria/breadcrumbs@3.5.13":
|
||||
version "3.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.13.tgz#2686f7f460f20d67fe5cdfe185e32e3e78186962"
|
||||
@ -2023,6 +2071,18 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.6.tgz#193ced6a40c8006cfc1ca3f4553444fb38f0e543"
|
||||
integrity sha512-OpXEVoCKSS3lQqjx9GGGOapBeuW5eUboYHRlHP9urXPX25IKZ6AnP5ZRxtVf63iieUbsHxLn8NQ5Nlftc6yzAA==
|
||||
|
||||
"@types/webidl-conversions@*":
|
||||
version "7.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz#1306dbfa53768bcbcfc95a1c8cde367975581859"
|
||||
integrity sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==
|
||||
|
||||
"@types/whatwg-url@^11.0.2":
|
||||
version "11.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-11.0.5.tgz#aaa2546e60f0c99209ca13360c32c78caf2c409f"
|
||||
integrity sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==
|
||||
dependencies:
|
||||
"@types/webidl-conversions" "*"
|
||||
|
||||
abab@^2.0.5, abab@^2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz"
|
||||
@ -2158,6 +2218,11 @@ browser-process-hrtime@^1.0.0:
|
||||
resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
|
||||
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
|
||||
|
||||
bson@^6.7.0:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/bson/-/bson-6.8.0.tgz#5063c41ba2437c2b8ff851b50d9e36cb7aaa7525"
|
||||
integrity sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==
|
||||
|
||||
busboy@1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz"
|
||||
@ -2852,6 +2917,11 @@ mathjs@^13.0.2:
|
||||
tiny-emitter "^2.1.0"
|
||||
typed-function "^4.2.1"
|
||||
|
||||
memory-pager@^1.0.2:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
|
||||
integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
|
||||
|
||||
merge2@^1.3.0:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
||||
@ -2926,6 +2996,23 @@ mkdirp@^1.0.3:
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
|
||||
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
|
||||
|
||||
mongodb-connection-string-url@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz#c13e6ac284ae401752ebafdb8cd7f16c6723b141"
|
||||
integrity sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==
|
||||
dependencies:
|
||||
"@types/whatwg-url" "^11.0.2"
|
||||
whatwg-url "^13.0.0"
|
||||
|
||||
mongodb@^6.8.0:
|
||||
version "6.8.0"
|
||||
resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-6.8.0.tgz#680450f113cdea6d2d9f7121fe57cd29111fd2ce"
|
||||
integrity sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==
|
||||
dependencies:
|
||||
"@mongodb-js/saslprep" "^1.1.5"
|
||||
bson "^6.7.0"
|
||||
mongodb-connection-string-url "^3.0.0"
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
|
||||
@ -3134,12 +3221,19 @@ postcss@^8, postcss@^8.4.23:
|
||||
picocolors "^1.0.0"
|
||||
source-map-js "^1.2.0"
|
||||
|
||||
prisma@^5.17.0:
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.17.0.tgz#267b43921ab94805b010537cffa5ccaf530fa066"
|
||||
integrity sha512-m4UWkN5lBE6yevqeOxEvmepnL5cNPEjzMw2IqDB59AcEV6w7D8vGljDLd1gPFH+W6gUxw9x7/RmN5dCS/WTPxA==
|
||||
dependencies:
|
||||
"@prisma/engines" "5.17.0"
|
||||
|
||||
psl@^1.1.33:
|
||||
version "1.9.0"
|
||||
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
|
||||
integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
|
||||
|
||||
punycode@^2.1.1:
|
||||
punycode@^2.1.1, punycode@^2.3.0:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
|
||||
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
|
||||
@ -3378,6 +3472,13 @@ source-map@~0.6.1:
|
||||
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
|
||||
integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
|
||||
|
||||
sparse-bitfield@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
|
||||
integrity sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==
|
||||
dependencies:
|
||||
memory-pager "^1.0.2"
|
||||
|
||||
streamsearch@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz"
|
||||
@ -3563,6 +3664,13 @@ tr46@^3.0.0:
|
||||
dependencies:
|
||||
punycode "^2.1.1"
|
||||
|
||||
tr46@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-4.1.1.tgz#281a758dcc82aeb4fe38c7dfe4d11a395aac8469"
|
||||
integrity sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==
|
||||
dependencies:
|
||||
punycode "^2.3.0"
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
@ -3690,6 +3798,14 @@ whatwg-url@^11.0.0:
|
||||
tr46 "^3.0.0"
|
||||
webidl-conversions "^7.0.0"
|
||||
|
||||
whatwg-url@^13.0.0:
|
||||
version "13.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-13.0.0.tgz#b7b536aca48306394a34e44bda8e99f332410f8f"
|
||||
integrity sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==
|
||||
dependencies:
|
||||
tr46 "^4.1.1"
|
||||
webidl-conversions "^7.0.0"
|
||||
|
||||
whatwg-url@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user