메뉴 공통기능(텍스트, 치수선, 거리측정) 작업

This commit is contained in:
yjnoh 2024-10-21 18:12:53 +09:00
parent fd0fc1ed6e
commit 51096a150d
3 changed files with 381 additions and 5 deletions

View File

@ -10,16 +10,21 @@ import QSelectBox from '@/components/common/select/QSelectBox'
import { useMessage } from '@/hooks/useMessage'
import { usePlan } from '@/hooks/usePlan'
import { useSwal } from '@/hooks/useSwal'
import { useEvent } from '@/hooks/useEvent'
import { canvasState, canvasZoomState, currentCanvasPlanState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
import { wordDisplaySelector } from '@/store/settingAtom'
import { MENU } from '@/common/common'
import { checkLineOrientation, getDistance } from '@/util/canvas-util'
import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
import { lineSegment } from '@turf/turf'
const canvasMenus = [
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
@ -68,11 +73,20 @@ export default function CanvasMenu(props) {
const globalLocale = useRecoilValue(globalLocaleStore)
const canvas = useRecoilValue(canvasState)
const sessionState = useRecoilValue(sessionStore)
const wordDisplay = useRecoilValue(wordDisplaySelector)
const { getMessage } = useMessage()
const { saveCanvas } = usePlan()
const { swalFire } = useSwal()
const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent()
const [commonFunction, setCommonFunction] = useState(null)
const [commonFunctionState, setCommonFunctionState] = useState({
text: false,
dimension: false,
distance: false,
})
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
const onClickNav = (menu) => {
setMenuNumber(menu.index)
@ -155,6 +169,328 @@ export default function CanvasMenu(props) {
canvas.renderAll()
}
const commonTextMode = () => {
let textbox
if (commonFunctionState.text) {
addCanvasMouseEventListener('mouse:down', (event) => {
const pointer = canvas?.getPointer(event.e)
textbox = new fabric.Textbox('', {
left: pointer.x,
top: pointer.y,
width: 200,
fontSize: 14,
editable: true,
name: 'commonText',
visible: wordDisplay,
})
canvas?.add(textbox)
canvas.setActiveObject(textbox)
textbox.enterEditing()
textbox.selectAll()
})
addDocumentEventListener('keydown', document, (e) => {
if (e.key === 'Enter') {
if (commonFunctionState.text) {
const activeObject = canvas.getActiveObject()
if (activeObject && activeObject.isEditing) {
if (activeObject.text === '') {
canvas?.remove(activeObject)
} else {
activeObject.exitEditing()
}
//
const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText')
texts.forEach((text) => {
text.set({ editable: false })
})
canvas.renderAll()
}
}
}
})
}
}
const commonDimensionMode = () => {
if (commonFunctionState.dimension) {
let points = []
let distanceText = null
let minX, minY, maxX, maxY
//
function createArrow(x, y, angle) {
return new fabric.Triangle({
left: x,
top: y,
originX: 'center',
originY: 'center',
angle: angle,
width: 15,
height: 15,
fill: 'black',
selectable: false,
})
}
const circleOptions = {
radius: 5,
strokeWidth: 2,
stroke: 'red',
fill: 'white',
selectable: false,
}
const lineOptions = {
stroke: 'black',
strokeWidth: 2,
selectable: false,
}
//
addCanvasMouseEventListener('mouse:down', (e) => {
const pointer = canvas.getPointer(e.e)
let point
if (points.length === 0) {
//
point = new fabric.Circle({
left: pointer.x - 5, //
top: pointer.y - 5, //
...circleOptions,
})
points.push(point)
canvas.add(point)
} else if (points.length === 1) {
//
const p1 = points[0]
const deltaX = Math.abs(pointer.x - (p1.left + p1.radius))
const deltaY = Math.abs(pointer.y - (p1.top + p1.radius))
if (deltaX > deltaY) {
// (y )
point = new fabric.Circle({
left: pointer.x - 5, //
top: p1.top, // y
...circleOptions,
})
} else {
// (x )
point = new fabric.Circle({
left: p1.left, // x
top: pointer.y - 5, //
...circleOptions,
})
}
points.push(point)
canvas.add(point)
//
const p2 = points[1]
const p1CenterX = p1.left + p1.radius
const p1CenterY = p1.top + p1.radius
const p2CenterX = p2.left + p2.radius
const p2CenterY = p2.top + p2.radius
points.forEach((point) => {
canvas?.remove(point)
})
// ( )
const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions)
canvas.add(line)
const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
const lineDirection = checkLineOrientation(line)
let extendLine = []
if (lineDirection === 'horizontal') {
extendLine = [
[line.x1, line.y1 - 20, line.x1, line.y1 + 20],
[line.x2, line.y2 - 20, line.x2, line.y2 + 20],
]
} else {
extendLine = [
[line.x1 - 20, line.y1, line.x1 + 20, line.y1],
[line.x2 - 20, line.y2, line.x2 + 20, line.y2],
]
}
extendLine.forEach((line) => {
const extendLine = new fabric.Line(line, lineOptions)
canvas.add(extendLine)
})
//
// const angle = calculateAngle({ x: p1CenterX, y: p1CenterY }, { x: p2CenterX, y: p2CenterY })
//
const arrow1 = createArrow(p1CenterX + 7.5, p1CenterY + 1, lineDirection === 'horizontal' ? -90 : 0) //
const arrow2 = createArrow(p2CenterX - 6.5, p2CenterY + 1, lineDirection === 'horizontal' ? 90 : 180) //
canvas.add(arrow1)
canvas.add(arrow2)
//
// ,
distanceText = new fabric.Text(`${distance}`, {
left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15),
top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0),
fill: 'black',
fontSize: 16,
selectable: true,
textAlign: 'center',
originX: 'center',
originY: 'center',
angle: lineDirection === 'horizontal' ? 0 : 270,
// lockMovementX: false,
// lockMovementY: false,
})
canvas.add(distanceText)
// minX = p1CenterX
// maxX = p2CenterX
// minY = p1CenterY
// maxY = p2CenterY
// ,
points = []
}
//
canvas.renderAll()
})
// addCanvasMouseEventListener('object:moving', function (e) {
// const obj = e.target
// if (obj.left < minX) {
// obj.left = minX
// }
// if (obj.left + obj.width > maxX) {
// obj.left = maxX - obj.width
// }
// if (obj.top < minY) {
// obj.top = minY
// }
// if (obj.top + obj.height > maxY) {
// obj.top = maxY - obj.height
// }
// })
}
}
const commonDistanceMode = () => {
if (commonFunctionState.distance) {
let points = []
let distanceText = null
const circleOptions = {
radius: 5,
strokeWidth: 2,
stroke: 'red',
fill: 'white',
selectable: false,
}
const lineOptions = {
stroke: 'black',
strokeWidth: 2,
selectable: false,
strokeDashArray: [9, 5],
}
const textOptions = {
fill: 'black',
fontSize: 16,
selectable: true,
textAlign: 'center',
originX: 'center',
originY: 'center',
}
//
addCanvasMouseEventListener('mouse:down', function (options) {
const pointer = canvas.getPointer(options.e)
let point
if (points.length === 0) {
//
point = new fabric.Circle({
left: pointer.x - 5, //
top: pointer.y - 5, //
...circleOptions,
})
points.push(point)
canvas.add(point)
} else if (points.length === 1) {
//
const p1 = points[0]
point = new fabric.Circle({
left: pointer.x - 5, //
top: pointer.y - 5, //
...circleOptions,
})
points.push(point)
canvas.add(point)
//
const p2 = points[1]
const p1CenterX = p1.left + p1.radius
const p1CenterY = p1.top + p1.radius
const p2CenterX = p2.left + p2.radius
const p2CenterY = p2.top + p2.radius
const p3 = new fabric.Point(p2CenterX, p1CenterY)
// ( )
const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions)
const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions)
const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions)
canvas.add(line)
canvas.add(line2)
canvas.add(line3)
const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY)
const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y)
const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY)
// ,
distanceText = new fabric.Text(`${distance1}`, {
left: (p1CenterX + p2CenterX) / 2,
top: (p1CenterY + p2CenterY) / 2,
...textOptions,
})
canvas.add(distanceText)
distanceText = new fabric.Text(`${distance2}`, {
left: (p2CenterX + p3.x) / 2,
top: (p2CenterY + p3.y) / 2,
...textOptions,
})
canvas.add(distanceText)
distanceText = new fabric.Text(`${distance3}`, {
left: (p3.x + p1CenterX) / 2,
top: (p3.y + p1CenterY) / 2,
...textOptions,
})
canvas.add(distanceText)
// ,
points = []
}
//
canvas.renderAll()
})
}
}
useEffect(() => {
if (globalLocale === 'ko') {
setAppMessageState(KO)
@ -163,6 +499,35 @@ export default function CanvasMenu(props) {
}
}, [menuNumber, type, globalLocale])
const commonFunctions = (mode) => {
let tempStates = { ...commonFunctionState }
if (tempStates[mode]) {
tempStates[mode] = false
} else {
Object.keys(tempStates).forEach((key) => {
tempStates[key] = false
})
if (mode !== undefined) {
tempStates[mode] = true
}
}
setCommonFunctionState(tempStates)
}
useEffect(() => {
initEvent()
if (commonFunctionState.text) {
commonTextMode()
} else if (commonFunctionState.dimension) {
commonDimensionMode()
} else if (commonFunctionState.distance) {
commonDistanceMode()
}
}, [commonFunctionState])
return (
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
<div className="canvas-menu-inner">
@ -192,9 +557,9 @@ export default function CanvasMenu(props) {
</div>
}
<div className="btn-from">
<button className="btn01" onClick={() => {}}></button>
<button className="btn02 active"></button>
<button className="btn03 "></button>
<button className={`btn01 ${commonFunctionState.text ? 'active' : ''}`} onClick={() => commonFunctions('text')}></button>
<button className={`btn02 ${commonFunctionState.dimension ? 'active' : ''} `} onClick={() => commonFunctions('dimension')}></button>
<button className={`btn03 ${commonFunctionState.distance ? 'active' : ''} `} onClick={() => commonFunctions('distance')}></button>
</div>
<div className="select-box">
<QSelectBox title={'瓦53A'} option={SelectOption} />

View File

@ -575,7 +575,8 @@ export function useSurfaceShapeBatch() {
obj.name === BATCH_TYPE.OPENING ||
obj.name === BATCH_TYPE.SHADOW ||
obj.name === BATCH_TYPE.TRIANGLE_DORMER ||
obj.name === BATCH_TYPE.PENTAGON_DORMER
obj.name === BATCH_TYPE.PENTAGON_DORMER ||
obj.name === 'lengthText'
) {
canvas?.remove(obj)
}

View File

@ -78,7 +78,7 @@ export const getCenterPoint = (point1, point2) => {
* @returns
*/
export const getDistance = (x1, y1, x2, y2) => {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)).toFixed(0)
}
// polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수
@ -853,3 +853,13 @@ export function setSurfaceShapePattern(polygon) {
polygon.set('fill', pattern)
polygon.canvas?.renderAll()
}
export function checkLineOrientation(line) {
if (line.y1 === line.y2) {
return 'horizontal' // 수평
} else if (line.x1 === line.x2) {
return 'vertical' // 수직
} else {
return 'diagonal' // 대각선
}
}