Merge branch 'dev' into dev-yj
This commit is contained in:
commit
896a0baa7e
@ -1 +1,3 @@
|
|||||||
NEXT_PUBLIC_TEST="테스트변수입니다. development"
|
NEXT_PUBLIC_TEST="테스트변수입니다. development"
|
||||||
|
|
||||||
|
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
||||||
@ -1 +1,3 @@
|
|||||||
NEXT_PUBLIC_TEST="테스트변수입니다. production"
|
NEXT_PUBLIC_TEST="테스트변수입니다. production"
|
||||||
|
|
||||||
|
NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
|
||||||
@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nextui-org/react": "^2.4.2",
|
"@nextui-org/react": "^2.4.2",
|
||||||
"@prisma/client": "^5.17.0",
|
"@prisma/client": "^5.17.0",
|
||||||
|
"axios": "^1.7.3",
|
||||||
"fabric": "^5.3.0",
|
"fabric": "^5.3.0",
|
||||||
"framer-motion": "^11.2.13",
|
"framer-motion": "^11.2.13",
|
||||||
"mathjs": "^13.0.2",
|
"mathjs": "^13.0.2",
|
||||||
|
|||||||
@ -1,12 +1,18 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import { Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@nextui-org/react'
|
import { Button, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@nextui-org/react'
|
||||||
import Hero from '@/components/Hero'
|
import Hero from '@/components/Hero'
|
||||||
import QSelect from '@/components/ui/QSelect'
|
import QSelect from '@/components/ui/QSelect'
|
||||||
import styles from './changelog.module.css'
|
import styles from './changelog.module.css'
|
||||||
|
import { get } from '@/lib/Axios'
|
||||||
|
|
||||||
export default function changelogPage() {
|
export default function changelogPage() {
|
||||||
const testVar = process.env.NEXT_PUBLIC_TEST
|
const testVar = process.env.NEXT_PUBLIC_TEST
|
||||||
|
|
||||||
|
const handleUsers = async () => {
|
||||||
|
const users = await get('/api/user/find-all')
|
||||||
|
console.log(users)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hero title="Change log" />
|
<Hero title="Change log" />
|
||||||
@ -32,10 +38,15 @@ export default function changelogPage() {
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-2 py-4">
|
<div className="m-2">
|
||||||
<QSelect />
|
<QSelect />
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full bg-orange-300 py-4">{testVar}</div>
|
<div className="w-full bg-orange-300 m-2">{testVar}</div>
|
||||||
|
<div>
|
||||||
|
<div className="m-2">
|
||||||
|
<Button onClick={handleUsers}>Button</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,11 +6,12 @@ import QRect from '@/components/fabric/QRect'
|
|||||||
|
|
||||||
import RangeSlider from './ui/RangeSlider'
|
import RangeSlider from './ui/RangeSlider'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { canvasSizeState, fontSizeState, roofState, sortedPolygonArray } from '@/store/canvasAtom'
|
import { canvasSizeState, fontSizeState, roofMaterialState, roofState, sortedPolygonArray } from '@/store/canvasAtom'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
||||||
import { calculateIntersection } from '@/util/canvas-util'
|
import { calculateIntersection } from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
import offsetPolygon from '@/util/qpolygon-utils'
|
||||||
|
|
||||||
export default function Roof2() {
|
export default function Roof2() {
|
||||||
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
|
||||||
@ -31,7 +32,8 @@ export default function Roof2() {
|
|||||||
|
|
||||||
const [showControl, setShowControl] = useState(false)
|
const [showControl, setShowControl] = useState(false)
|
||||||
|
|
||||||
const roof = useRecoilValue(roofState)
|
//지붕재
|
||||||
|
const roofMaterial = useRecoilValue(roofMaterialState)
|
||||||
|
|
||||||
const {
|
const {
|
||||||
mode,
|
mode,
|
||||||
@ -138,12 +140,12 @@ export default function Roof2() {
|
|||||||
{ x: 100, y: 400 },
|
{ x: 100, y: 400 },
|
||||||
]
|
]
|
||||||
const type2 = [
|
const type2 = [
|
||||||
{ x: 100, y: 100 },
|
{ x: 200, y: 100 },
|
||||||
{ x: 100, y: 1000 },
|
{ x: 200, y: 1000 },
|
||||||
{ x: 1000, y: 1000 },
|
{ x: 1100, y: 1000 },
|
||||||
{ x: 1000, y: 600 },
|
{ x: 1100, y: 600 },
|
||||||
{ x: 550, y: 600 },
|
{ x: 650, y: 600 },
|
||||||
{ x: 550, y: 100 },
|
{ x: 650, y: 100 },
|
||||||
]
|
]
|
||||||
|
|
||||||
const type3 = [
|
const type3 = [
|
||||||
@ -263,58 +265,17 @@ export default function Roof2() {
|
|||||||
{ x: 675, y: 275 },
|
{ x: 675, y: 275 },
|
||||||
{ x: 450, y: 850 },
|
{ x: 450, y: 850 },
|
||||||
]
|
]
|
||||||
const polygon = new QPolygon(type4, {
|
const polygon = new QPolygon(type2, {
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
strokeWidth: 1,
|
strokeWidth: 1,
|
||||||
selectable: false,
|
selectable: false,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
name: 'QPolygon1',
|
name: 'wall',
|
||||||
})
|
})
|
||||||
|
|
||||||
canvas?.add(polygon)
|
canvas?.add(polygon)
|
||||||
|
|
||||||
polygon.set('strokeDashArray', [10, 5, 2, 5])
|
|
||||||
polygon.set('stroke', 'blue')
|
|
||||||
polygon.set('strokeWidth', 1)
|
|
||||||
|
|
||||||
// const newPolygon = fabric.util.clone(polygon)
|
|
||||||
|
|
||||||
handleOuterlinesTest2(polygon)
|
handleOuterlinesTest2(polygon)
|
||||||
|
|
||||||
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
|
||||||
|
|
||||||
roofs.forEach((roof) => {
|
|
||||||
let maxLengthLine = roof.lines.reduce((acc, cur) => {
|
|
||||||
return acc.length > cur.length ? acc : cur
|
|
||||||
})
|
|
||||||
|
|
||||||
// 패턴 소스를 위한 임시 캔버스 생성
|
|
||||||
const patternSourceCanvas = document.createElement('canvas')
|
|
||||||
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
|
||||||
patternSourceCanvas.width = 20 * window.devicePixelRatio || 1
|
|
||||||
patternSourceCanvas.height = 10 * window.devicePixelRatio || 1
|
|
||||||
} else {
|
|
||||||
patternSourceCanvas.width = 10 * window.devicePixelRatio || 1
|
|
||||||
patternSourceCanvas.height = 20 * window.devicePixelRatio || 1
|
|
||||||
}
|
|
||||||
|
|
||||||
const ctx = patternSourceCanvas.getContext('2d')
|
|
||||||
|
|
||||||
// 벽돌 패턴 그리기
|
|
||||||
ctx.scale(window.devicePixelRatio || 1, window.devicePixelRatio || 1)
|
|
||||||
ctx.strokeStyle = 'green'
|
|
||||||
ctx.lineWidth = 0.4
|
|
||||||
ctx.strokeRect(0, 0, 100, 100)
|
|
||||||
// 패턴 생성
|
|
||||||
const pattern = new fabric.Pattern({
|
|
||||||
source: patternSourceCanvas,
|
|
||||||
repeat: 'repeat',
|
|
||||||
})
|
|
||||||
|
|
||||||
roof.set('fill', pattern)
|
|
||||||
})
|
|
||||||
|
|
||||||
// const lines = togglePolygonLine(polygon)
|
// const lines = togglePolygonLine(polygon)
|
||||||
// togglePolygonLine(lines[0])
|
// togglePolygonLine(lines[0])
|
||||||
}
|
}
|
||||||
@ -404,6 +365,70 @@ export default function Roof2() {
|
|||||||
handleClear()
|
handleClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const drawRoofMaterial = () => {
|
||||||
|
const { width, height, roofStyle } = roofMaterial
|
||||||
|
|
||||||
|
const wallPolygon = canvas?.getObjects().find((obj) => obj.name === 'wall')
|
||||||
|
|
||||||
|
wallPolygon.set('strokeDashArray', [10, 5, 2, 5])
|
||||||
|
wallPolygon.set('stroke', 'blue')
|
||||||
|
wallPolygon.set('strokeWidth', 1)
|
||||||
|
|
||||||
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
||||||
|
|
||||||
|
roofs.forEach((roof) => {
|
||||||
|
let maxLengthLine = roof.lines.reduce((acc, cur) => {
|
||||||
|
return acc.length > cur.length ? acc : cur
|
||||||
|
})
|
||||||
|
|
||||||
|
const roofRatio = window.devicePixelRatio || 1
|
||||||
|
|
||||||
|
// 패턴 소스를 위한 임시 캔버스 생성
|
||||||
|
const patternSourceCanvas = document.createElement('canvas')
|
||||||
|
if (roofStyle === 1) {
|
||||||
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
|
patternSourceCanvas.width = width * roofRatio
|
||||||
|
patternSourceCanvas.height = height * roofRatio
|
||||||
|
} else {
|
||||||
|
patternSourceCanvas.width = height * roofRatio
|
||||||
|
patternSourceCanvas.height = width * roofRatio
|
||||||
|
}
|
||||||
|
} else if (roofStyle === 2) {
|
||||||
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
|
patternSourceCanvas.width = width * 2
|
||||||
|
patternSourceCanvas.height = height * 2
|
||||||
|
} else {
|
||||||
|
patternSourceCanvas.width = height * 2
|
||||||
|
patternSourceCanvas.height = width * 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ctx = patternSourceCanvas.getContext('2d')
|
||||||
|
|
||||||
|
ctx.scale(roofRatio, roofRatio)
|
||||||
|
ctx.strokeStyle = 'green'
|
||||||
|
ctx.lineWidth = 0.4
|
||||||
|
// 벽돌 패턴 그리기
|
||||||
|
if (roofStyle === 1) {
|
||||||
|
ctx.strokeRect(0, 0, 50, 30)
|
||||||
|
} else if (roofStyle === 2) {
|
||||||
|
// 지그재그
|
||||||
|
ctx.strokeRect(0, 0, 200, 100)
|
||||||
|
ctx.strokeRect(100, 100, 200, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 생성
|
||||||
|
const pattern = new fabric.Pattern({
|
||||||
|
source: patternSourceCanvas,
|
||||||
|
repeat: 'repeat',
|
||||||
|
})
|
||||||
|
roof.set('fill', null)
|
||||||
|
|
||||||
|
roof.set('fill', pattern)
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* canvas 내용 불러오기
|
* canvas 내용 불러오기
|
||||||
*/
|
*/
|
||||||
@ -424,6 +449,34 @@ export default function Roof2() {
|
|||||||
makeRoofPatternPolygon(roofStyle)
|
makeRoofPatternPolygon(roofStyle)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const createRoofRack = () => {
|
||||||
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof')
|
||||||
|
roofs.forEach((roof) => {
|
||||||
|
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, {
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: 'red',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: true,
|
||||||
|
fontSize: fontSize,
|
||||||
|
name: 'wall',
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(newPoly)
|
||||||
|
|
||||||
|
if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') {
|
||||||
|
newPoly.fillCell({ width: 100, height: 50, padding: 10 })
|
||||||
|
} else {
|
||||||
|
newPoly.fillCell({ width: 50, height: 100, padding: 10 })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{canvas && (
|
{canvas && (
|
||||||
@ -530,6 +583,12 @@ export default function Roof2() {
|
|||||||
<Button className="m-1 p-2" onClick={addCanvas}>
|
<Button className="m-1 p-2" onClick={addCanvas}>
|
||||||
캔버스 추가
|
캔버스 추가
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button className="m-1 p-2" onClick={drawRoofMaterial}>
|
||||||
|
지붕타입 지붕재
|
||||||
|
</Button>
|
||||||
|
<Button className="m-1 p-2" onClick={createRoofRack}>
|
||||||
|
지붕가대
|
||||||
|
</Button>
|
||||||
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
|
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
|
||||||
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
|
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -13,6 +13,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
hips: [],
|
hips: [],
|
||||||
ridges: [],
|
ridges: [],
|
||||||
connectRidges: [],
|
connectRidges: [],
|
||||||
|
cells: [],
|
||||||
initialize: function (points, options, canvas) {
|
initialize: function (points, options, canvas) {
|
||||||
// 소수점 전부 제거
|
// 소수점 전부 제거
|
||||||
points.forEach((point) => {
|
points.forEach((point) => {
|
||||||
@ -234,7 +235,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
{ x: rectLeft, y: rectTop + rectHeight },
|
{ x: rectLeft, y: rectTop + rectHeight },
|
||||||
{ x: rectLeft + rectWidth, y: rectTop + rectHeight },
|
{ x: rectLeft + rectWidth, y: rectTop + rectHeight },
|
||||||
]
|
]
|
||||||
|
|
||||||
const allPointsInside = rectPoints.every((point) => this.inPolygon(point))
|
const allPointsInside = rectPoints.every((point) => this.inPolygon(point))
|
||||||
|
|
||||||
if (allPointsInside) {
|
if (allPointsInside) {
|
||||||
@ -244,6 +244,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
width: rectWidth,
|
width: rectWidth,
|
||||||
height: rectHeight,
|
height: rectHeight,
|
||||||
fill: '#BFFD9F',
|
fill: '#BFFD9F',
|
||||||
|
stroke: 'black',
|
||||||
selectable: true, // 선택 가능하게 설정
|
selectable: true, // 선택 가능하게 설정
|
||||||
lockMovementX: true, // X 축 이동 잠금
|
lockMovementX: true, // X 축 이동 잠금
|
||||||
lockMovementY: true, // Y 축 이동 잠금
|
lockMovementY: true, // Y 축 이동 잠금
|
||||||
@ -251,17 +252,24 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
lockScalingX: true, // X 축 크기 조정 잠금
|
lockScalingX: true, // X 축 크기 조정 잠금
|
||||||
lockScalingY: true, // Y 축 크기 조정 잠금
|
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||||
opacity: 0.8,
|
opacity: 0.8,
|
||||||
|
name: 'cell',
|
||||||
})
|
})
|
||||||
|
|
||||||
|
rect.on('mousedown', () => {
|
||||||
|
rect.set({ fill: 'red' })
|
||||||
|
})
|
||||||
|
|
||||||
drawCellsArray.push(rect) //배열에 넣어서 반환한다
|
drawCellsArray.push(rect) //배열에 넣어서 반환한다
|
||||||
this.canvas.add(rect)
|
this.canvas.add(rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.canvas?.renderAll()
|
this.canvas?.renderAll()
|
||||||
|
this.cells = drawCellsArray
|
||||||
return drawCellsArray
|
return drawCellsArray
|
||||||
},
|
},
|
||||||
inPolygon(point) {
|
inPolygon(point) {
|
||||||
const vertices = this.getCurrentPoints()
|
const vertices = this.points
|
||||||
let intersects = 0
|
let intersects = 0
|
||||||
|
|
||||||
for (let i = 0; i < vertices.length; i++) {
|
for (let i = 0; i < vertices.length; i++) {
|
||||||
|
|||||||
@ -542,7 +542,24 @@ export function useCanvas(id) {
|
|||||||
const addCanvas = () => {
|
const addCanvas = () => {
|
||||||
// const canvasState = canvas
|
// const canvasState = canvas
|
||||||
|
|
||||||
const objs = canvas?.toJSON(['selectable', 'name', 'parentId', 'id', 'length', 'idx', 'direction', 'lines', 'points'])
|
const objs = canvas?.toJSON([
|
||||||
|
'selectable',
|
||||||
|
'name',
|
||||||
|
'parentId',
|
||||||
|
'id',
|
||||||
|
'length',
|
||||||
|
'idx',
|
||||||
|
'direction',
|
||||||
|
'lines',
|
||||||
|
'points',
|
||||||
|
'lockMovementX',
|
||||||
|
'lockMovementY',
|
||||||
|
'lockRotation',
|
||||||
|
'lockScalingX',
|
||||||
|
'lockScalingY',
|
||||||
|
'opacity',
|
||||||
|
'cells',
|
||||||
|
])
|
||||||
|
|
||||||
const str = JSON.stringify(objs)
|
const str = JSON.stringify(objs)
|
||||||
|
|
||||||
@ -552,16 +569,12 @@ export function useCanvas(id) {
|
|||||||
// 역직렬화하여 캔버스에 객체를 다시 추가합니다.
|
// 역직렬화하여 캔버스에 객체를 다시 추가합니다.
|
||||||
canvas?.loadFromJSON(JSON.parse(str), function () {
|
canvas?.loadFromJSON(JSON.parse(str), function () {
|
||||||
// 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
|
// 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
|
||||||
|
console.log(canvas?.getObjects().filter((obj) => obj.name === 'roof'))
|
||||||
canvas?.renderAll() // 캔버스를 다시 그립니다.
|
canvas?.renderAll() // 캔버스를 다시 그립니다.
|
||||||
})
|
})
|
||||||
}, 1000)
|
}, 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
const changeCanvas = (idx) => {
|
|
||||||
canvas?.clear()
|
|
||||||
const canvasState = JSON.parse(canvasList[idx])
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
canvas,
|
canvas,
|
||||||
addShape,
|
addShape,
|
||||||
@ -577,6 +590,5 @@ export function useCanvas(id) {
|
|||||||
handleFlip,
|
handleFlip,
|
||||||
setCanvasBackgroundWithDots,
|
setCanvasBackgroundWithDots,
|
||||||
addCanvas,
|
addCanvas,
|
||||||
changeCanvas,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ import {
|
|||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
import offsetPolygon from '@/util/qpolygon-utils'
|
||||||
|
|
||||||
export const Mode = {
|
export const Mode = {
|
||||||
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
|
DRAW_LINE: 'drawLine', // 기준선 긋기모드`
|
||||||
@ -1113,66 +1114,13 @@ export function useMode() {
|
|||||||
*벽 지붕 외곽선 생성 polygon을 입력받아 만들기
|
*벽 지붕 외곽선 생성 polygon을 입력받아 만들기
|
||||||
*/
|
*/
|
||||||
const handleOuterlinesTest2 = (polygon, offset = 71) => {
|
const handleOuterlinesTest2 = (polygon, offset = 71) => {
|
||||||
const offsetPoints = []
|
const offsetPoints = offsetPolygon(polygon.points, 50)
|
||||||
const sortedIndex = getStartIndex(polygon.lines)
|
|
||||||
let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex)
|
|
||||||
|
|
||||||
if (tmpArraySorted[0].direction === 'right') {
|
const roof = makePolygon(
|
||||||
//시계방향
|
offsetPoints.map((point) => {
|
||||||
tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정
|
return { x1: point.x, y1: point.y }
|
||||||
}
|
}),
|
||||||
|
)
|
||||||
setSortedArray(tmpArraySorted) //recoil에 넣음
|
|
||||||
|
|
||||||
const points = tmpArraySorted.map((line) => ({
|
|
||||||
x: line.x1,
|
|
||||||
y: line.y1,
|
|
||||||
}))
|
|
||||||
|
|
||||||
for (let i = 0; i < points.length; i++) {
|
|
||||||
const prev = points[(i - 1 + points.length) % points.length]
|
|
||||||
const current = points[i]
|
|
||||||
const next = points[(i + 1) % points.length]
|
|
||||||
|
|
||||||
// 두 벡터 계산 (prev -> current, current -> next)
|
|
||||||
const vector1 = { x: current.x - prev.x, y: current.y - prev.y }
|
|
||||||
const vector2 = { x: next.x - current.x, y: next.y - current.y }
|
|
||||||
|
|
||||||
// 벡터의 길이 계산
|
|
||||||
const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y)
|
|
||||||
const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y)
|
|
||||||
|
|
||||||
// 벡터를 단위 벡터로 정규화
|
|
||||||
const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 }
|
|
||||||
const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 }
|
|
||||||
|
|
||||||
// 법선 벡터 계산 (왼쪽 방향)
|
|
||||||
const normal1 = { x: -unitVector1.y, y: unitVector1.x }
|
|
||||||
const normal2 = { x: -unitVector2.y, y: unitVector2.x }
|
|
||||||
|
|
||||||
// 법선 벡터 평균 계산
|
|
||||||
const averageNormal = {
|
|
||||||
x: (normal1.x + normal2.x) / 2,
|
|
||||||
y: (normal1.y + normal2.y) / 2,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 평균 법선 벡터를 단위 벡터로 정규화
|
|
||||||
const lengthNormal = Math.sqrt(averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y)
|
|
||||||
const unitNormal = {
|
|
||||||
x: averageNormal.x / lengthNormal,
|
|
||||||
y: averageNormal.y / lengthNormal,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 오프셋 적용
|
|
||||||
const offsetPoint = {
|
|
||||||
x1: current.x + unitNormal.x * offset,
|
|
||||||
y1: current.y + unitNormal.y * offset,
|
|
||||||
}
|
|
||||||
|
|
||||||
offsetPoints.push(offsetPoint)
|
|
||||||
}
|
|
||||||
|
|
||||||
const roof = makePolygon(offsetPoints)
|
|
||||||
roof.setWall(polygon)
|
roof.setWall(polygon)
|
||||||
setRoof(roof)
|
setRoof(roof)
|
||||||
|
|
||||||
|
|||||||
56
src/lib/Axios.js
Normal file
56
src/lib/Axios.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
'use client'
|
||||||
|
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
axios.defaults.baseURL = process.env.NEXT_PUBLIC_API_SERVER_PATH
|
||||||
|
|
||||||
|
const axiosInstance = axios.create({
|
||||||
|
// baseURL: process.env.API_SERVER_URL,
|
||||||
|
headers: {
|
||||||
|
Accept: 'application/json',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use((config) => {
|
||||||
|
// config['Authorization'] = localStorage.getItem('token')
|
||||||
|
//TODO: 인터셉터에서 추가 로직 구현
|
||||||
|
return config
|
||||||
|
})
|
||||||
|
|
||||||
|
axiosInstance.interceptors.request.use(undefined, (error) => {
|
||||||
|
//TODO: 인터셉터에서 에러 처리 로직 구현
|
||||||
|
// if (error.isAxiosError && e.response?.status === 401) {
|
||||||
|
// localStorage.removeItem('token')
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
|
||||||
|
export const get = (url) =>
|
||||||
|
axiosInstance
|
||||||
|
.get(url)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const post = (url, data) =>
|
||||||
|
axiosInstance
|
||||||
|
.post(url, data)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const put = (url, data) =>
|
||||||
|
axiosInstance
|
||||||
|
.put(url, data)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const patch = (url, data) =>
|
||||||
|
axiosInstance
|
||||||
|
.patch(url, data)
|
||||||
|
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
|
|
||||||
|
export const del = (url) =>
|
||||||
|
axiosInstance
|
||||||
|
.delete(url)
|
||||||
|
.then((res) => res.data)
|
||||||
|
.catch(console.error)
|
||||||
@ -60,3 +60,10 @@ export const drewRoofCellsState = atom({
|
|||||||
default: [],
|
default: [],
|
||||||
dangerouslyAllowMutability: true,
|
dangerouslyAllowMutability: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 지붕재 width, height, rafter(서까래), roofStyle을 갖고있고 roofStyle 1은 정방향, 2는 지그재그
|
||||||
|
export const roofMaterialState = atom({
|
||||||
|
key: 'roofMaterial',
|
||||||
|
default: { width: 20, height: 10, rafter: 0, roofStyle: 2 },
|
||||||
|
dangerouslyAllowMutability: true,
|
||||||
|
})
|
||||||
|
|||||||
@ -3,6 +3,8 @@ import { QLine } from '@/components/fabric/QLine'
|
|||||||
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util'
|
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
|
||||||
|
const TWO_PI = Math.PI * 2
|
||||||
|
|
||||||
export const defineQPloygon = () => {
|
export const defineQPloygon = () => {
|
||||||
fabric.QPolygon.fromObject = function (object, callback) {
|
fabric.QPolygon.fromObject = function (object, callback) {
|
||||||
fabric.Object._fromObject('QPolygon', object, callback, 'points')
|
fabric.Object._fromObject('QPolygon', object, callback, 'points')
|
||||||
@ -499,6 +501,10 @@ export const dividePolygon = (polygon) => {
|
|||||||
const startHip = hips.find((hip) => hip.startPoint.x === startPoint.x && hip.startPoint.y === startPoint.y)
|
const startHip = hips.find((hip) => hip.startPoint.x === startPoint.x && hip.startPoint.y === startPoint.y)
|
||||||
const endHip = hips.find((hip) => hip.startPoint.x === endPoint.x && hip.startPoint.y === endPoint.y)
|
const endHip = hips.find((hip) => hip.startPoint.x === endPoint.x && hip.startPoint.y === endPoint.y)
|
||||||
|
|
||||||
|
if (!startHip || !endHip) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (startHip && endHip && startHip.endPoint.x === endHip.endPoint.x && startHip.endPoint.y === endHip.endPoint.y) {
|
if (startHip && endHip && startHip.endPoint.x === endHip.endPoint.x && startHip.endPoint.y === endHip.endPoint.y) {
|
||||||
polygonPoints.push(startHip.endPoint)
|
polygonPoints.push(startHip.endPoint)
|
||||||
|
|
||||||
@ -506,7 +512,7 @@ export const dividePolygon = (polygon) => {
|
|||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
id: polygon.id,
|
id: polygon.id,
|
||||||
name: 'roof',
|
name: 'roof',
|
||||||
selectable: true,
|
selectable: false,
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
@ -535,7 +541,7 @@ export const dividePolygon = (polygon) => {
|
|||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
id: polygon.id,
|
id: polygon.id,
|
||||||
name: 'roof',
|
name: 'roof',
|
||||||
selectable: true,
|
selectable: false,
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
@ -553,7 +559,7 @@ export const dividePolygon = (polygon) => {
|
|||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
id: polygon.id,
|
id: polygon.id,
|
||||||
name: 'roof',
|
name: 'roof',
|
||||||
selectable: true,
|
selectable: false,
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
@ -628,7 +634,7 @@ export const dividePolygon = (polygon) => {
|
|||||||
fontSize: polygon.fontSize,
|
fontSize: polygon.fontSize,
|
||||||
id: polygon.id,
|
id: polygon.id,
|
||||||
name: 'roof',
|
name: 'roof',
|
||||||
selectable: true,
|
selectable: false,
|
||||||
stroke: 'black',
|
stroke: 'black',
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
strokeWidth: 3,
|
strokeWidth: 3,
|
||||||
@ -672,3 +678,239 @@ const getOneSideLine = (line) => {
|
|||||||
|
|
||||||
return newLine
|
return newLine
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function inwardEdgeNormal(vertex1, vertex2) {
|
||||||
|
// Assuming that polygon vertices are in clockwise order
|
||||||
|
const dx = vertex2.x - vertex1.x
|
||||||
|
const dy = vertex2.y - vertex1.y
|
||||||
|
const edgeLength = Math.sqrt(dx * dx + dy * dy)
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: -dy / edgeLength,
|
||||||
|
y: dx / edgeLength,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function outwardEdgeNormal(vertex1, vertex2) {
|
||||||
|
var n = inwardEdgeNormal(vertex1, vertex2)
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: -n.x,
|
||||||
|
y: -n.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPolygon(vertices) {
|
||||||
|
const edges = []
|
||||||
|
let minX = vertices.length > 0 ? vertices[0].x : undefined
|
||||||
|
let minY = vertices.length > 0 ? vertices[0].y : undefined
|
||||||
|
let maxX = minX
|
||||||
|
let maxY = minY
|
||||||
|
|
||||||
|
for (let i = 0; i < vertices.length; i++) {
|
||||||
|
const vertex1 = vertices[i]
|
||||||
|
const vertex2 = vertices[(i + 1) % vertices.length]
|
||||||
|
|
||||||
|
const outwardNormal = outwardEdgeNormal(vertex1, vertex2)
|
||||||
|
|
||||||
|
const inwardNormal = inwardEdgeNormal(vertex1, vertex2)
|
||||||
|
|
||||||
|
const edge = {
|
||||||
|
vertex1,
|
||||||
|
vertex2,
|
||||||
|
index: i,
|
||||||
|
outwardNormal,
|
||||||
|
inwardNormal,
|
||||||
|
}
|
||||||
|
|
||||||
|
edges.push(edge)
|
||||||
|
|
||||||
|
const x = vertices[i].x
|
||||||
|
const y = vertices[i].y
|
||||||
|
minX = Math.min(x, minX)
|
||||||
|
minY = Math.min(y, minY)
|
||||||
|
maxX = Math.max(x, maxX)
|
||||||
|
maxY = Math.max(y, maxY)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
vertices,
|
||||||
|
edges,
|
||||||
|
minX,
|
||||||
|
minY,
|
||||||
|
maxX,
|
||||||
|
maxY,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// based on http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/, edgeA => "line a", edgeB => "line b"
|
||||||
|
|
||||||
|
function edgesIntersection(edgeA, edgeB) {
|
||||||
|
const den =
|
||||||
|
(edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) -
|
||||||
|
(edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y)
|
||||||
|
|
||||||
|
if (den == 0) {
|
||||||
|
return null // lines are parallel or coincident
|
||||||
|
}
|
||||||
|
|
||||||
|
const ua =
|
||||||
|
((edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
|
||||||
|
(edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
|
||||||
|
den
|
||||||
|
|
||||||
|
const ub =
|
||||||
|
((edgeA.vertex2.x - edgeA.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
|
||||||
|
(edgeA.vertex2.y - edgeA.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
|
||||||
|
den
|
||||||
|
|
||||||
|
// Edges are not intersecting but the lines defined by them are
|
||||||
|
const isIntersectionOutside = ua < 0 || ub < 0 || ua > 1 || ub > 1
|
||||||
|
|
||||||
|
return {
|
||||||
|
x: edgeA.vertex1.x + ua * (edgeA.vertex2.x - edgeA.vertex1.x),
|
||||||
|
y: edgeA.vertex1.y + ua * (edgeA.vertex2.y - edgeA.vertex1.y),
|
||||||
|
isIntersectionOutside,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendArc(arcSegments, vertices, center, radius, startVertex, endVertex, isPaddingBoundary) {
|
||||||
|
var startAngle = Math.atan2(startVertex.y - center.y, startVertex.x - center.x)
|
||||||
|
var endAngle = Math.atan2(endVertex.y - center.y, endVertex.x - center.x)
|
||||||
|
|
||||||
|
if (startAngle < 0) {
|
||||||
|
startAngle += TWO_PI
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endAngle < 0) {
|
||||||
|
endAngle += TWO_PI
|
||||||
|
}
|
||||||
|
|
||||||
|
const angle = startAngle > endAngle ? startAngle - endAngle : startAngle + TWO_PI - endAngle
|
||||||
|
const angleStep = (isPaddingBoundary ? -angle : TWO_PI - angle) / arcSegments
|
||||||
|
|
||||||
|
vertices.push(startVertex)
|
||||||
|
|
||||||
|
for (let i = 1; i < arcSegments; ++i) {
|
||||||
|
const angle = startAngle + angleStep * i
|
||||||
|
|
||||||
|
const vertex = {
|
||||||
|
x: center.x + Math.cos(angle) * radius,
|
||||||
|
y: center.y + Math.sin(angle) * radius,
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices.push(vertex)
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices.push(endVertex)
|
||||||
|
}
|
||||||
|
|
||||||
|
function createOffsetEdge(edge, dx, dy) {
|
||||||
|
return {
|
||||||
|
vertex1: {
|
||||||
|
x: edge.vertex1.x + dx,
|
||||||
|
y: edge.vertex1.y + dy,
|
||||||
|
},
|
||||||
|
vertex2: {
|
||||||
|
x: edge.vertex2.x + dx,
|
||||||
|
y: edge.vertex2.y + dy,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createMarginPolygon(polygon, offset, arcSegments = 0) {
|
||||||
|
const offsetEdges = []
|
||||||
|
|
||||||
|
for (let i = 0; i < polygon.edges.length; i++) {
|
||||||
|
const edge = polygon.edges[i]
|
||||||
|
const dx = edge.outwardNormal.x * offset
|
||||||
|
const dy = edge.outwardNormal.y * offset
|
||||||
|
offsetEdges.push(createOffsetEdge(edge, dx, dy))
|
||||||
|
}
|
||||||
|
|
||||||
|
const vertices = []
|
||||||
|
|
||||||
|
for (let i = 0; i < offsetEdges.length; i++) {
|
||||||
|
const thisEdge = offsetEdges[i]
|
||||||
|
const prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length]
|
||||||
|
const vertex = edgesIntersection(prevEdge, thisEdge)
|
||||||
|
|
||||||
|
if (vertex && (!vertex.isIntersectionOutside || arcSegments < 1)) {
|
||||||
|
vertices.push({
|
||||||
|
x: vertex.x,
|
||||||
|
y: vertex.y,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const arcCenter = polygon.edges[i].vertex1
|
||||||
|
|
||||||
|
appendArc(arcSegments, vertices, arcCenter, offset, prevEdge.vertex2, thisEdge.vertex1, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const marginPolygon = createPolygon(vertices)
|
||||||
|
|
||||||
|
marginPolygon.offsetEdges = offsetEdges
|
||||||
|
|
||||||
|
return marginPolygon
|
||||||
|
}
|
||||||
|
|
||||||
|
function createPaddingPolygon(polygon, offset, arcSegments = 0) {
|
||||||
|
const offsetEdges = []
|
||||||
|
|
||||||
|
for (let i = 0; i < polygon.edges.length; i++) {
|
||||||
|
const edge = polygon.edges[i]
|
||||||
|
const dx = edge.inwardNormal.x * offset
|
||||||
|
const dy = edge.inwardNormal.y * offset
|
||||||
|
offsetEdges.push(createOffsetEdge(edge, dx, dy))
|
||||||
|
}
|
||||||
|
|
||||||
|
const vertices = []
|
||||||
|
|
||||||
|
for (let i = 0; i < offsetEdges.length; i++) {
|
||||||
|
const thisEdge = offsetEdges[i]
|
||||||
|
const prevEdge = offsetEdges[(i + offsetEdges.length - 1) % offsetEdges.length]
|
||||||
|
const vertex = edgesIntersection(prevEdge, thisEdge)
|
||||||
|
if (vertex && (!vertex.isIntersectionOutside || arcSegments < 1)) {
|
||||||
|
vertices.push({
|
||||||
|
x: vertex.x,
|
||||||
|
y: vertex.y,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
const arcCenter = polygon.edges[i].vertex1
|
||||||
|
|
||||||
|
appendArc(arcSegments, vertices, arcCenter, offset, prevEdge.vertex2, thisEdge.vertex1, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const paddingPolygon = createPolygon(vertices)
|
||||||
|
|
||||||
|
paddingPolygon.offsetEdges = offsetEdges
|
||||||
|
|
||||||
|
return paddingPolygon
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function offsetPolygon(vertices, offset, arcSegments = 0) {
|
||||||
|
const polygon = createPolygon(vertices)
|
||||||
|
|
||||||
|
const originPolygon = new QPolygon(vertices, { fontSize: 0 })
|
||||||
|
|
||||||
|
if (offset > 0) {
|
||||||
|
let result = createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||||
|
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
|
||||||
|
|
||||||
|
if (allPointsOutside) {
|
||||||
|
return createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||||
|
} else {
|
||||||
|
return createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let result = createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||||
|
const allPointsInside = result.every((point) => originPolygon.inPolygon(point))
|
||||||
|
|
||||||
|
if (allPointsInside) {
|
||||||
|
return createPaddingPolygon(polygon, offset, arcSegments).vertices
|
||||||
|
} else {
|
||||||
|
return createMarginPolygon(polygon, offset, arcSegments).vertices
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
19
yarn.lock
19
yarn.lock
@ -2181,6 +2181,15 @@ asynckit@^0.4.0:
|
|||||||
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
|
||||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||||
|
|
||||||
|
axios@^1.7.3:
|
||||||
|
version "1.7.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.3.tgz#a1125f2faf702bc8e8f2104ec3a76fab40257d85"
|
||||||
|
integrity sha512-Ar7ND9pU99eJ9GpoGQKhKf58GpUOgnzuaB7ueNQ5BMi0p+LZ5oaEnfF999fAArcTIBwXTCHAmGcHOZJaWPq9Nw==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.15.6"
|
||||||
|
form-data "^4.0.0"
|
||||||
|
proxy-from-env "^1.1.0"
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
|
||||||
@ -2539,6 +2548,11 @@ flat@^5.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
|
resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241"
|
||||||
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
|
integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==
|
||||||
|
|
||||||
|
follow-redirects@^1.15.6:
|
||||||
|
version "1.15.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
|
||||||
|
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
|
||||||
|
|
||||||
foreground-child@^3.1.0:
|
foreground-child@^3.1.0:
|
||||||
version "3.2.1"
|
version "3.2.1"
|
||||||
resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz"
|
resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz"
|
||||||
@ -3233,6 +3247,11 @@ prisma@^5.17.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@prisma/engines" "5.17.0"
|
"@prisma/engines" "5.17.0"
|
||||||
|
|
||||||
|
proxy-from-env@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
|
||||||
|
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
|
||||||
|
|
||||||
psl@^1.1.33:
|
psl@^1.1.33:
|
||||||
version "1.9.0"
|
version "1.9.0"
|
||||||
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
|
resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user