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

# Conflicts:
#	src/components/fabric/QPolygon.js
This commit is contained in:
Jaeyoung Lee 2024-07-19 20:31:50 +09:00
commit a061ec018d
9 changed files with 1494 additions and 322 deletions

View File

@ -12,6 +12,7 @@
"@nextui-org/react": "^2.4.2",
"fabric": "^5.3.0",
"framer-motion": "^11.2.13",
"mathjs": "^13.0.2",
"next": "14.2.3",
"react": "^18",
"react-dom": "^18",

View File

@ -169,7 +169,7 @@ export default function Roof2() {
{ x: 1088, y: 42 },
]
if (canvas) {
const polygon = new QPolygon(type1, {
const polygon = new QPolygon(type4, {
fill: 'transparent',
stroke: 'black',
strokeWidth: 1,

View File

@ -13,6 +13,9 @@ export class QLine extends fabric.Group {
idx
type = 'QLine'
parent
isAlreadyInterSection = false
interSectionPoints = []
#lengthTxt = 0
constructor(points, option = { isActiveLengthText: true }, lengthTxt) {

View File

@ -1,6 +1,7 @@
import { fabric } from 'fabric'
import {
calculateIntersection,
calculateIntersection2,
distanceBetweenPoints,
findClosestLineToPoint,
findTopTwoIndexesByDistance,
@ -530,13 +531,97 @@ export default class QPolygon extends fabric.Group {
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]
// 두 점의 좌표
@ -550,8 +635,139 @@ 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: 'green',
idx: index,
})
this.addWithUpdate(line)
helpLines.push(line)
this.canvas.renderAll()
})
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) {
return
}
line.set({ isAlreadyInterSection: true })
nextLine.set({ isAlreadyInterSection: true })
const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], {
fontSize: this.fontSize,
stroke: 'skyblue',
})
const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
fontSize: this.fontSize,
stroke: 'skyblue',
})
ridgeStartPoints.push(intersectionPoint)
this.addWithUpdate(helpLine1)
this.addWithUpdate(helpLine2)
this.removeWithUpdate(nextLine)
this.removeWithUpdate(line)
this.canvas.renderAll()
})
// 안만나는 선들
const notInterSectionLines = helpLines.filter((line) => !line.isAlreadyInterSection)
const ridgeEndPoints = []
const interSectionPoints = []
notInterSectionLines.forEach((line, index) => {
line.line.set({ strokeWidth: (index + 1) * 5 })
centerLines.forEach((centerLine) => {
const interSectionPoint = calculateIntersection2(line, centerLine)
if (!this.inPolygon(interSectionPoint) || !interSectionPoint) {
return
}
line.interSectionPoints.push(interSectionPoint)
interSectionPoints.push(interSectionPoint)
})
})
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',
})
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
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,

File diff suppressed because it is too large Load Diff

View File

@ -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 templatePolygonArrayState = atom({
key: 'templatePolygon',
default: {}, //object ex) big, mid, sht = {point : [{x1, y1}, {x2, y1}], direction : left or right or top or bottom}
})

View File

@ -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,30 +26,21 @@ 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
}
// define a function that can keep the polygon in the same position when we change its width/height/top/left
export function anchorWrapper(anchorIndex, fn) {
return function (eventData, transform, x, y) {
return function(eventData, transform, x, y) {
let fabricObject = transform.target
let originX =
fabricObject?.points[anchorIndex].x - fabricObject.pathOffset.x
let 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,40 @@ 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)
return { x: Math.round(intersectionX), y: Math.round(intersectionY) }
}
return { x: intersectX, y: intersectY }
return null // 교차점이 선분의 범위 내에 없음
}
export const calculateIntersection2 = (line1, line2) => {
const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2])
return { x: Math.round(result[0]), y: Math.round(result[1]) }
}
function findOrthogonalPoint(x1, y1, x2, y2, x3, y3, x4, y4) {
// 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))
const intersectionY =
((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
const intersectionX = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
const intersectionY = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
return { x: intersectionX, y: intersectionY }
}
@ -399,9 +366,7 @@ export const sortedPoints = (points) => {
// 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,
)
const max = temp.reduce((prev, current) => (prev.x >= current.x ? prev : current))
resultPoints.push(max)
currentPoint = max
copyPoints.splice(copyPoints.indexOf(max), 1)
@ -414,9 +379,7 @@ export const sortedPoints = (points) => {
// 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,
)
const max = temp.reduce((prev, current) => (prev.y >= current.y ? prev : current))
resultPoints.push(max)
currentPoint = max
@ -481,9 +444,7 @@ 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
}
}

2
startscript.js Normal file
View File

@ -0,0 +1,2 @@
var exec = require('child_process').exec
exec('yarn start', { windowsHide: true })

View File

@ -14,6 +14,13 @@
dependencies:
regenerator-runtime "^0.14.0"
"@babel/runtime@^7.24.7":
version "7.24.8"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.8.tgz#5d958c3827b13cc6d05e038c07fb2e5e3420d82e"
integrity sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==
dependencies:
regenerator-runtime "^0.14.0"
"@formatjs/ecma402-abstract@2.0.0":
version "2.0.0"
resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.0.0.tgz#39197ab90b1c78b7342b129a56a7acdb8f512e17"
@ -2262,6 +2269,11 @@ commander@^4.0.0:
resolved "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz"
integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
complex.js@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.1.1.tgz#0675dac8e464ec431fb2ab7d30f41d889fb25c31"
integrity sha512-8njCHOTtFFLtegk6zQo0kkVX1rngygb/KQI6z1qZxlFI3scluC+LVTCFbrkWjBv4vvLlbQ9t88IPMC6k95VTTg==
compute-scroll-into-view@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz#753f11d972596558d8fe7c6bcbc8497690ab4c87"
@ -2324,7 +2336,7 @@ debug@4:
dependencies:
ms "2.1.2"
decimal.js@^10.3.1:
decimal.js@^10.3.1, decimal.js@^10.4.3:
version "10.4.3"
resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz"
integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==
@ -2393,6 +2405,11 @@ emoji-regex@^9.2.2:
resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz"
integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
escape-latex@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/escape-latex/-/escape-latex-1.2.0.tgz#07c03818cf7dac250cce517f4fda1b001ef2bca1"
integrity sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==
escodegen@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz"
@ -2474,6 +2491,11 @@ form-data@^4.0.0:
combined-stream "^1.0.8"
mime-types "^2.1.12"
fraction.js@^4.3.7:
version "4.3.7"
resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7"
integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==
framer-motion@^11.2.13:
version "11.2.13"
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-11.2.13.tgz#ab23fbc386233b1a1548757d840190054e5e1f1d"
@ -2703,6 +2725,11 @@ jackspeak@^3.1.2:
optionalDependencies:
"@pkgjs/parseargs" "^0.11.0"
javascript-natural-sort@^0.7.1:
version "0.7.1"
resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59"
integrity sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==
jiti@^1.21.0:
version "1.21.6"
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz"
@ -2810,6 +2837,21 @@ make-dir@^3.1.0:
dependencies:
semver "^6.0.0"
mathjs@^13.0.2:
version "13.0.2"
resolved "https://registry.yarnpkg.com/mathjs/-/mathjs-13.0.2.tgz#eb87e31a21d9ffc57e26ce98ddb14a4a07b13d91"
integrity sha512-8vK/+InU4FTphRTWsrnvRsgSjbyNupRQYDDIXLuEGDZtJsGdbA9dVV4HZ0amBQb+RXplRjVJNGZZfB0WoHWFWA==
dependencies:
"@babel/runtime" "^7.24.7"
complex.js "^2.1.1"
decimal.js "^10.4.3"
escape-latex "^1.2.0"
fraction.js "^4.3.7"
javascript-natural-sort "^0.7.1"
seedrandom "^3.0.5"
tiny-emitter "^2.1.0"
typed-function "^4.2.1"
merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
@ -3263,6 +3305,11 @@ scroll-into-view-if-needed@3.0.10:
dependencies:
compute-scroll-into-view "^3.0.2"
seedrandom@^3.0.5:
version "3.0.5"
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7"
integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==
semver@^6.0.0:
version "6.3.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
@ -3370,7 +3417,14 @@ string_decoder@^1.1.1:
dependencies:
safe-buffer "~5.2.0"
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
dependencies:
ansi-regex "^5.0.1"
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@ -3480,6 +3534,11 @@ thenify-all@^1.0.0:
dependencies:
any-promise "^1.0.0"
tiny-emitter@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.1.0.tgz#1d1a56edfc51c43e863cbb5382a72330e3555423"
integrity sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==
to-regex-range@^5.0.1:
version "5.0.1"
resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
@ -3519,6 +3578,11 @@ tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0:
resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz"
integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==
typed-function@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/typed-function/-/typed-function-4.2.1.tgz#19aa51847aa2dea9ef5e7fb7641c060179a74426"
integrity sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==
universalify@^0.2.0:
version "0.2.0"
resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz"