템플릿 추가 및 이벤트 수정
This commit is contained in:
parent
1b9f850c64
commit
085e1ff51e
File diff suppressed because it is too large
Load Diff
@ -1,108 +0,0 @@
|
|||||||
import { fabric } from 'fabric'
|
|
||||||
|
|
||||||
export class QLine extends fabric.Group {
|
|
||||||
line
|
|
||||||
text
|
|
||||||
fontSize
|
|
||||||
length = 0
|
|
||||||
x1
|
|
||||||
y1
|
|
||||||
x2
|
|
||||||
y2
|
|
||||||
direction
|
|
||||||
type = 'HelpLine'
|
|
||||||
parent
|
|
||||||
#lengthTxt = 0
|
|
||||||
|
|
||||||
constructor(points, option, lengthTxt) {
|
|
||||||
const [x1, y1, x2, y2] = points
|
|
||||||
|
|
||||||
if (!option.fontSize) {
|
|
||||||
throw new Error('Font size is required.')
|
|
||||||
}
|
|
||||||
|
|
||||||
const line = new fabric.Line(points, { ...option, strokeWidth: 1 })
|
|
||||||
super([line], {})
|
|
||||||
|
|
||||||
this.x1 = x1
|
|
||||||
this.y1 = y1
|
|
||||||
this.x2 = x2
|
|
||||||
this.y2 = y2
|
|
||||||
this.line = line
|
|
||||||
this.fontSize = option.fontSize
|
|
||||||
this.direction = option.direction
|
|
||||||
this.parent = option.parent
|
|
||||||
|
|
||||||
if (lengthTxt > 0) {
|
|
||||||
this.#lengthTxt = Number(lengthTxt)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.#init()
|
|
||||||
this.#addControl()
|
|
||||||
}
|
|
||||||
|
|
||||||
#init() {
|
|
||||||
this.#addLengthText(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
#addControl() {
|
|
||||||
this.on('moving', () => {
|
|
||||||
this.#addLengthText(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.on('modified', (e) => {
|
|
||||||
this.#addLengthText(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
this.on('selected', () => {
|
|
||||||
Object.keys(this.controls).forEach((controlKey) => {
|
|
||||||
if (controlKey !== 'ml' && controlKey !== 'mr') {
|
|
||||||
this.setControlVisible(controlKey, false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#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(), {
|
|
||||||
left: (this.x1 + this.x2) / 2,
|
|
||||||
top: (this.y1 + this.y2) / 2,
|
|
||||||
fontSize: this.fontSize,
|
|
||||||
})
|
|
||||||
this.length = this.#lengthTxt
|
|
||||||
this.text = text
|
|
||||||
this.addWithUpdate(text)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const scaleX = this.scaleX
|
|
||||||
const scaleY = this.scaleY
|
|
||||||
const x1 = this.left
|
|
||||||
const y1 = this.top
|
|
||||||
const x2 = this.left + this.width * scaleX
|
|
||||||
const y2 = this.top + this.height * scaleY
|
|
||||||
const dx = x2 - x1
|
|
||||||
const dy = y2 - y1
|
|
||||||
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
|
|
||||||
|
|
||||||
const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
|
|
||||||
left: (x1 + x2) / 2,
|
|
||||||
top: (y1 + y2) / 2,
|
|
||||||
fontSize: this.fontSize,
|
|
||||||
})
|
|
||||||
this.text = text
|
|
||||||
this.addWithUpdate(text)
|
|
||||||
}
|
|
||||||
|
|
||||||
setFontSize(fontSize) {
|
|
||||||
this.fontSize = fontSize
|
|
||||||
this.text.set({ fontSize })
|
|
||||||
this.addWithUpdate()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -18,6 +18,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
parentId: null,
|
parentId: null,
|
||||||
innerLines: [],
|
innerLines: [],
|
||||||
children: [],
|
children: [],
|
||||||
|
initOptions: null,
|
||||||
initialize: function (points, options, canvas) {
|
initialize: function (points, options, canvas) {
|
||||||
// 소수점 전부 제거
|
// 소수점 전부 제거
|
||||||
points.forEach((point) => {
|
points.forEach((point) => {
|
||||||
@ -58,6 +59,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
this.canvas = canvas
|
this.canvas = canvas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.initOptions = options
|
||||||
|
|
||||||
this.init()
|
this.init()
|
||||||
this.initLines()
|
this.initLines()
|
||||||
this.setShape()
|
this.setShape()
|
||||||
@ -177,7 +180,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
|
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
|
||||||
|
|
||||||
// Create new text object if it doesn't exist
|
// Create new text object if it doesn't exist
|
||||||
const text = new fabric.Text(length.toFixed(0), {
|
const text = new fabric.IText(length.toFixed(0), {
|
||||||
left: midPoint.x,
|
left: midPoint.x,
|
||||||
top: midPoint.y,
|
top: midPoint.y,
|
||||||
fontSize: this.fontSize,
|
fontSize: this.fontSize,
|
||||||
@ -189,7 +192,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
parentDirection: getDirectionByPoint(start, end),
|
parentDirection: getDirectionByPoint(start, end),
|
||||||
parentDegree: degree,
|
parentDegree: degree,
|
||||||
dirty: true,
|
dirty: true,
|
||||||
editable: false,
|
editable: true,
|
||||||
selectable: true,
|
selectable: true,
|
||||||
lockRotation: true,
|
lockRotation: true,
|
||||||
lockScalingX: true,
|
lockScalingX: true,
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { useEffect, useState } from 'react'
|
|||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { canvasSizeState, currentObjectState, modeState } from '@/store/canvasAtom'
|
import { canvasSizeState, currentObjectState, modeState } from '@/store/canvasAtom'
|
||||||
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
|
||||||
// 캔버스에 필요한 이벤트
|
// 캔버스에 필요한 이벤트
|
||||||
export function useCanvasEvent() {
|
export function useCanvasEvent() {
|
||||||
@ -77,11 +78,55 @@ export function useCanvasEvent() {
|
|||||||
if (target.name === 'lengthText') {
|
if (target.name === 'lengthText') {
|
||||||
const x = target.left
|
const x = target.left
|
||||||
const y = target.top
|
const y = target.top
|
||||||
|
// Add a property to store the previous value
|
||||||
|
const previousValue = target.text
|
||||||
target.on('selected', (e) => {
|
target.on('selected', (e) => {
|
||||||
Object.keys(target.controls).forEach((controlKey) => {
|
Object.keys(target.controls).forEach((controlKey) => {
|
||||||
target.setControlVisible(controlKey, false)
|
target.setControlVisible(controlKey, false)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
target.on('editing:exited', () => {
|
||||||
|
if (isNaN(target.text.trim())) {
|
||||||
|
target.set({ text: previousValue })
|
||||||
|
canvas?.renderAll()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const updatedValue = parseFloat(target.text.trim())
|
||||||
|
const targetParent = target.parent
|
||||||
|
const points = targetParent.getCurrentPoints()
|
||||||
|
const i = target.idx // Assuming target.index gives the index of the point
|
||||||
|
|
||||||
|
const startPoint = points[i]
|
||||||
|
const endPoint = points[(i + 1) % points.length]
|
||||||
|
|
||||||
|
const dx = endPoint.x - startPoint.x
|
||||||
|
const dy = endPoint.y - startPoint.y
|
||||||
|
|
||||||
|
const currentLength = Math.sqrt(dx * dx + dy * dy)
|
||||||
|
const scaleFactor = updatedValue / currentLength
|
||||||
|
|
||||||
|
const newEndPoint = {
|
||||||
|
x: startPoint.x + dx * scaleFactor,
|
||||||
|
y: startPoint.y + dy * scaleFactor,
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPoints = [...points]
|
||||||
|
newPoints[(i + 1) % points.length] = newEndPoint
|
||||||
|
|
||||||
|
for (let idx = i + 1; idx < points.length; idx++) {
|
||||||
|
if (newPoints[idx].x === endPoint.x) {
|
||||||
|
newPoints[idx].x = newEndPoint.x
|
||||||
|
} else if (newPoints[idx].y === endPoint.y) {
|
||||||
|
newPoints[idx].y = newEndPoint.y
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newPolygon = new QPolygon(newPoints, targetParent.initOptions)
|
||||||
|
canvas?.add(newPolygon)
|
||||||
|
canvas?.remove(targetParent)
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
|
||||||
target.on('moving', (e) => {
|
target.on('moving', (e) => {
|
||||||
if (target.parentDirection === 'left' || target.parentDirection === 'right') {
|
if (target.parentDirection === 'left' || target.parentDirection === 'right') {
|
||||||
const minX = target.minX
|
const minX = target.minX
|
||||||
@ -116,7 +161,6 @@ export function useCanvasEvent() {
|
|||||||
if (whiteList.includes(e.target.name)) {
|
if (whiteList.includes(e.target.name)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
console.log('removed', e)
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -101,6 +101,8 @@ export function useMode() {
|
|||||||
}, [endPoint])
|
}, [endPoint])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
canvas?.off('mouse:out', removeMouseLines)
|
||||||
|
canvas?.on('mouse:out', removeMouseLines)
|
||||||
changeMode(canvas, mode)
|
changeMode(canvas, mode)
|
||||||
canvas?.off('mouse:move')
|
canvas?.off('mouse:move')
|
||||||
canvas?.on('mouse:move', drawMouseLines)
|
canvas?.on('mouse:move', drawMouseLines)
|
||||||
@ -160,6 +162,53 @@ export function useMode() {
|
|||||||
if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) {
|
if (mode === Mode.EDIT || mode === Mode.ADSORPTION_POINT) {
|
||||||
let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null
|
let adsorptionPoint = adsorptionPointList.length > 0 ? findClosestPoint(pointer, adsorptionPointList) : null
|
||||||
if ((horiGuideLines.length > 0 || vertGuideLines.length > 0) && guideDotMode) {
|
if ((horiGuideLines.length > 0 || vertGuideLines.length > 0) && guideDotMode) {
|
||||||
|
const closestHorizontalLine = getClosestHorizontalLine(pointer, horiGuideLines)
|
||||||
|
const closetVerticalLine = getClosestVerticalLine(pointer, vertGuideLines)
|
||||||
|
let intersection = null
|
||||||
|
let intersectionDistance = Infinity
|
||||||
|
|
||||||
|
if (closestHorizontalLine && closetVerticalLine) {
|
||||||
|
intersection = calculateIntersection(closestHorizontalLine, closetVerticalLine)
|
||||||
|
if (intersection) {
|
||||||
|
intersectionDistance = distanceBetweenPoints(pointer, intersection)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let xDiff, yDiff
|
||||||
|
|
||||||
|
if (closetVerticalLine) {
|
||||||
|
xDiff = Math.abs(pointer.x - closetVerticalLine.x1)
|
||||||
|
}
|
||||||
|
if (closestHorizontalLine) {
|
||||||
|
yDiff = Math.abs(pointer.y - closestHorizontalLine.y1)
|
||||||
|
}
|
||||||
|
|
||||||
|
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
|
||||||
|
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
|
||||||
|
|
||||||
|
const xRate = x / guideLineLengthHori
|
||||||
|
const yRate = y / guideLineLengthVert
|
||||||
|
const isAttachX = xRate >= 0.4 && xRate <= 0.7
|
||||||
|
const isAttachY = yRate >= 0.4 && yRate <= 0.7
|
||||||
|
if (isAttachX && isAttachY) {
|
||||||
|
newX = Math.floor(pointer.x / guideLineLengthHori) * guideLineLengthHori + guideLineLengthHori / 2
|
||||||
|
newY = Math.floor(pointer.y / guideLineLengthVert) * guideLineLengthVert + guideLineLengthVert / 2
|
||||||
|
} else {
|
||||||
|
if (intersection && intersectionDistance < 20) {
|
||||||
|
newX = intersection.x
|
||||||
|
newY = intersection.y
|
||||||
|
} else {
|
||||||
|
if (Math.min(xDiff, yDiff) <= 20) {
|
||||||
|
if (xDiff < yDiff) {
|
||||||
|
newX = closetVerticalLine.x1
|
||||||
|
newY = pointer.y
|
||||||
|
} else {
|
||||||
|
newX = pointer.x
|
||||||
|
newY = closestHorizontalLine.y1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (guideDotMode) {
|
} else if (guideDotMode) {
|
||||||
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
|
const x = pointer.x - guideLineLengthHori * Math.floor(pointer.x / guideLineLengthHori)
|
||||||
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
|
const y = pointer.y - guideLineLengthVert * Math.floor(pointer.y / guideLineLengthVert)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user