Merge pull request '지붕 이동 시 보조선 길이 안따라 가는 현상 수정' (#771) from dev into dev-deploy
Reviewed-on: #771
This commit is contained in:
commit
548c55dc99
@ -95,6 +95,34 @@ export const QLine = fabric.util.createClass(fabric.Line, {
|
|||||||
if (this.attributes?.planeSize) {
|
if (this.attributes?.planeSize) {
|
||||||
thisText.set({ planeSize: this.attributes.planeSize, text: this.attributes.planeSize.toString() })
|
thisText.set({ planeSize: this.attributes.planeSize, text: this.attributes.planeSize.toString() })
|
||||||
}
|
}
|
||||||
|
// 라인이 이동했을 수 있으므로 위치도 재계산해서 업데이트한다.
|
||||||
|
const sX = this.scaleX
|
||||||
|
const sY = this.scaleY
|
||||||
|
const tx1 = this.left
|
||||||
|
const ty1 = this.top
|
||||||
|
const tx2 = this.left + this.width * sX
|
||||||
|
const ty2 = this.top + this.height * sY
|
||||||
|
let nLeft, nTop
|
||||||
|
if (this.direction === 'left' || this.direction === 'right') {
|
||||||
|
nLeft = (tx1 + tx2) / 2
|
||||||
|
nTop = (ty1 + ty2) / 2 + 10
|
||||||
|
} else if (this.direction === 'top' || this.direction === 'bottom') {
|
||||||
|
nLeft = (tx1 + tx2) / 2 + 10
|
||||||
|
nTop = (ty1 + ty2) / 2
|
||||||
|
} else {
|
||||||
|
// 대각선
|
||||||
|
nLeft = (tx1 + tx2) / 2
|
||||||
|
nTop = (ty1 + ty2) / 2
|
||||||
|
}
|
||||||
|
thisText.set({
|
||||||
|
left: nLeft,
|
||||||
|
top: nTop,
|
||||||
|
minX: this.left,
|
||||||
|
maxX: this.left + this.width,
|
||||||
|
minY: this.top,
|
||||||
|
maxY: this.top + this.length,
|
||||||
|
})
|
||||||
|
thisText.setCoords?.()
|
||||||
} else {
|
} else {
|
||||||
this.setLength()
|
this.setLength()
|
||||||
const scaleX = this.scaleX
|
const scaleX = this.scaleX
|
||||||
|
|||||||
@ -136,9 +136,59 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.on('modified', () => {
|
this.on('modified', () => {
|
||||||
|
// 드래그 종료 시점의 delta 계산 (mousedown 에서 저장한 값 사용)
|
||||||
|
const hasPreDrag = this._preDragLeft != null && this._preDragTop != null
|
||||||
|
const dxModified = hasPreDrag ? this.left - this._preDragLeft : 0
|
||||||
|
const dyModified = hasPreDrag ? this.top - this._preDragTop : 0
|
||||||
|
|
||||||
this.initLines()
|
this.initLines()
|
||||||
this.addLengthText()
|
this.addLengthText()
|
||||||
this.setCoords()
|
this.setCoords()
|
||||||
|
|
||||||
|
// 보조선 / 자식 객체들도 같이 이동시킨다 (ROOF 가 아닌 WALL 등에서도 동작하도록)
|
||||||
|
if ((dxModified !== 0 || dyModified !== 0) && this.canvas) {
|
||||||
|
const directChildren = this.canvas.getObjects().filter((obj) => {
|
||||||
|
if (obj === this) return false
|
||||||
|
if (obj.parentId !== this.id) return false
|
||||||
|
if (obj.name === 'lengthText') return false
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
const childIds = new Set(directChildren.map((c) => c.id).filter(Boolean))
|
||||||
|
|
||||||
|
directChildren.forEach((obj) => {
|
||||||
|
const next = {}
|
||||||
|
if (obj.left != null) next.left = obj.left + dxModified
|
||||||
|
if (obj.top != null) next.top = obj.top + dyModified
|
||||||
|
if (obj.x1 != null) next.x1 = obj.x1 + dxModified
|
||||||
|
if (obj.y1 != null) next.y1 = obj.y1 + dyModified
|
||||||
|
if (obj.x2 != null) next.x2 = obj.x2 + dxModified
|
||||||
|
if (obj.y2 != null) next.y2 = obj.y2 + dyModified
|
||||||
|
obj.set(next)
|
||||||
|
if (obj.startPoint) obj.startPoint = { x: obj.startPoint.x + dxModified, y: obj.startPoint.y + dyModified }
|
||||||
|
if (obj.endPoint) obj.endPoint = { x: obj.endPoint.x + dxModified, y: obj.endPoint.y + dyModified }
|
||||||
|
obj.setCoords?.()
|
||||||
|
})
|
||||||
|
|
||||||
|
let movedTextCount = 0
|
||||||
|
this.canvas.getObjects().forEach((obj) => {
|
||||||
|
if (childIds.size > 0 && childIds.has(obj.parentId)) {
|
||||||
|
obj.set({ left: (obj.left ?? 0) + dxModified, top: (obj.top ?? 0) + dyModified })
|
||||||
|
if (obj.minX != null) obj.minX += dxModified
|
||||||
|
if (obj.maxX != null) obj.maxX += dxModified
|
||||||
|
if (obj.minY != null) obj.minY += dyModified
|
||||||
|
if (obj.maxY != null) obj.maxY += dyModified
|
||||||
|
obj.setCoords?.()
|
||||||
|
movedTextCount++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.canvas.renderAll()
|
||||||
|
|
||||||
|
// ROOF 의 경우 polygonMoved 가 같은 일을 다시 하므로, _preDragLeft 는 거기서 정리됨
|
||||||
|
if (this.name !== POLYGON_TYPE.ROOF) {
|
||||||
|
this._preDragLeft = null
|
||||||
|
this._preDragTop = null
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.on('selected', () => {
|
this.on('selected', () => {
|
||||||
@ -168,9 +218,20 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 드래그 시작 전 위치를 기록해두고 polygonMoved 에서 델타 계산용으로 사용
|
||||||
|
this.on('mousedown', () => {
|
||||||
|
this._preDragLeft = this.left
|
||||||
|
this._preDragTop = this.top
|
||||||
|
})
|
||||||
|
|
||||||
//QPolygon 좌표 이동시 좌표 재계산
|
//QPolygon 좌표 이동시 좌표 재계산
|
||||||
this.on('polygonMoved', () => {
|
this.on('polygonMoved', () => {
|
||||||
//폴리곤일때만 사용
|
//폴리곤일때만 사용
|
||||||
|
// 드래그 전 left/top 이 있으면 delta 계산, 없으면 0
|
||||||
|
const hasPreDrag = this._preDragLeft != null && this._preDragTop != null
|
||||||
|
const deltaX = hasPreDrag ? this.left - this._preDragLeft : 0
|
||||||
|
const deltaY = hasPreDrag ? this.top - this._preDragTop : 0
|
||||||
|
|
||||||
let matrix = this.calcTransformMatrix()
|
let matrix = this.calcTransformMatrix()
|
||||||
|
|
||||||
let transformedPoints = this.get('points')
|
let transformedPoints = this.get('points')
|
||||||
@ -204,6 +265,64 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
|
|
||||||
this.setCoords()
|
this.setCoords()
|
||||||
this.initLines()
|
this.initLines()
|
||||||
|
// 이동 후 기존 lengthText 가 이전 위치에 남아있지 않도록 재생성
|
||||||
|
this.addLengthText()
|
||||||
|
|
||||||
|
// 보조선(helpLine 등) 및 그 부속 객체(lengthText, pitchText 등)를 폴리곤 이동량만큼 같이 이동
|
||||||
|
if ((deltaX !== 0 || deltaY !== 0) && this.canvas) {
|
||||||
|
// drawHelpLine 이 추가하는 보조선들은 this.innerLines 배열에 들어가지 않을 수 있으므로
|
||||||
|
// canvas 에서 parentId === this.id 인 자식 객체들을 직접 찾는다.
|
||||||
|
// (단, 이 폴리곤의 outer lengthText 는 위에서 addLengthText() 로 이미 재생성했으므로 제외)
|
||||||
|
const directChildren = this.canvas.getObjects().filter((obj) => {
|
||||||
|
if (obj === this) return false
|
||||||
|
if (obj.parentId !== this.id) return false
|
||||||
|
if (obj.name === 'lengthText') return false // 이미 재생성됨
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
const childIds = new Set(directChildren.map((c) => c.id).filter(Boolean))
|
||||||
|
|
||||||
|
const translateLineLike = (obj) => {
|
||||||
|
const next = {}
|
||||||
|
if (obj.left != null) next.left = obj.left + deltaX
|
||||||
|
if (obj.top != null) next.top = obj.top + deltaY
|
||||||
|
if (obj.x1 != null) next.x1 = obj.x1 + deltaX
|
||||||
|
if (obj.y1 != null) next.y1 = obj.y1 + deltaY
|
||||||
|
if (obj.x2 != null) next.x2 = obj.x2 + deltaX
|
||||||
|
if (obj.y2 != null) next.y2 = obj.y2 + deltaY
|
||||||
|
obj.set(next)
|
||||||
|
if (obj.startPoint) {
|
||||||
|
obj.startPoint = { x: obj.startPoint.x + deltaX, y: obj.startPoint.y + deltaY }
|
||||||
|
}
|
||||||
|
if (obj.endPoint) {
|
||||||
|
obj.endPoint = { x: obj.endPoint.x + deltaX, y: obj.endPoint.y + deltaY }
|
||||||
|
}
|
||||||
|
obj.setCoords?.()
|
||||||
|
}
|
||||||
|
|
||||||
|
directChildren.forEach(translateLineLike)
|
||||||
|
|
||||||
|
// 보조선의 텍스트(lengthText, pitchText 등)는 보조선 line.id 를 parentId 로 가짐 -> 같이 이동
|
||||||
|
let movedTextCount = 0
|
||||||
|
this.canvas.getObjects().forEach((obj) => {
|
||||||
|
if (childIds.size > 0 && childIds.has(obj.parentId)) {
|
||||||
|
obj.set({
|
||||||
|
left: (obj.left ?? 0) + deltaX,
|
||||||
|
top: (obj.top ?? 0) + deltaY,
|
||||||
|
})
|
||||||
|
if (obj.minX != null) obj.minX += deltaX
|
||||||
|
if (obj.maxX != null) obj.maxX += deltaX
|
||||||
|
if (obj.minY != null) obj.minY += deltaY
|
||||||
|
if (obj.maxY != null) obj.maxY += deltaY
|
||||||
|
obj.setCoords?.()
|
||||||
|
movedTextCount++
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.canvas.renderAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
this._preDragLeft = null
|
||||||
|
this._preDragTop = null
|
||||||
})
|
})
|
||||||
|
|
||||||
// polygon.fillCell({ width: 50, height: 30, padding: 10 })
|
// polygon.fillCell({ width: 50, height: 30, padding: 10 })
|
||||||
|
|||||||
@ -239,7 +239,13 @@ export function useRoofFn() {
|
|||||||
let mousePos = canvas.getPointer(event.e)
|
let mousePos = canvas.getPointer(event.e)
|
||||||
mousePos = { x: Math.round(mousePos.x), y: Math.round(mousePos.y) }
|
mousePos = { x: Math.round(mousePos.x), y: Math.round(mousePos.y) }
|
||||||
|
|
||||||
const texts = canvas.getObjects().filter((obj) => obj.type === 'text' && (obj.attributes?.roofId === roof.id || obj.parentId === roof.id))
|
// 'text' 뿐 아니라 'textbox' (보조선의 lengthText 는 fabric.Textbox) 도 함께 제거.
|
||||||
|
// name 기반으로 필터링하는 게 더 안전하다.
|
||||||
|
const texts = canvas.getObjects().filter((obj) => {
|
||||||
|
const isTextObj = obj.type === 'text' || obj.type === 'textbox' || obj.name === 'lengthText' || obj.name === 'pitchText'
|
||||||
|
if (!isTextObj) return false
|
||||||
|
return obj.attributes?.roofId === roof.id || obj.parentId === roof.id
|
||||||
|
})
|
||||||
texts.forEach((text) => canvas.remove(text))
|
texts.forEach((text) => canvas.remove(text))
|
||||||
|
|
||||||
const allRoofObject = canvas
|
const allRoofObject = canvas
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user