외벽선 그리기 완료 후 offset 추가

This commit is contained in:
hyojun.choi 2024-10-02 15:41:22 +09:00
parent 7b6f5709d4
commit 0eaf973517
20 changed files with 204 additions and 89 deletions

View File

@ -6,6 +6,7 @@ import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/stor
import { fabric } from 'fabric'
import { ColorPicker, useColor } from 'react-color-palette'
import 'react-color-palette/css'
import { gridColorState } from '@/store/gridAtom'
export default function GridSettingsModal(props) {
const { canvasProps } = props
@ -23,7 +24,7 @@ export default function GridSettingsModal(props) {
const gridSettingArray = []
const [guideColor, setGuideColor] = useColor('rgb(200, 15, 15)')
const gridColor = useRecoilValue(gridColorState)
const [colorPickerShow, setColorPickerShow] = useState(false)
const boxStyle = {
@ -67,7 +68,7 @@ export default function GridSettingsModal(props) {
const horizontalLine = new fabric.Line(
[0, i * moduleVertLength - moduleVertLength / 2, canvasProps.width, i * moduleVertLength - moduleVertLength / 2],
{
stroke: guideColor.hex,
stroke: gridColor,
strokeWidth: 1,
selectable: true,
lockMovementX: true,
@ -89,7 +90,7 @@ export default function GridSettingsModal(props) {
const verticalLine = new fabric.Line(
[i * moduleHoriLength - moduleHoriLength / 2, 0, i * moduleHoriLength - moduleHoriLength / 2, canvasProps.height],
{
stroke: guideColor.hex,
stroke: gridColor,
strokeWidth: 1,
selectable: true,
lockMovementX: true,

View File

@ -13,7 +13,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
area: 0,
children: [],
initialize: function (points, options, canvas) {
this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? false })
this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? true })
if (options.id) {
this.id = options.id
} else {
@ -75,7 +75,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
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))
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10
},
addLengthText() {

View File

@ -27,6 +27,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
point.x = Math.round(point.x)
point.y = Math.round(point.y)
})
options.selectable = options.selectable ?? true
options.sort = options.sort ?? true
options.parentId = options.parentId ?? null
@ -51,6 +52,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
}
this.callSuper('initialize', points, options)
if (options.id) {
this.id = options.id
} else {
@ -164,6 +166,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
stroke: this.stroke,
strokeWidth: this.strokeWidth,
fontSize: this.fontSize,
attributes: {
offset: 0,
},
direction: getDirectionByPoint(point, nextPoint),
idx: i,
})
@ -193,14 +198,14 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const end = points[(i + 1) % points.length]
const dx = end.x - start.x
const dy = end.y - start.y
const length = Math.sqrt(dx * dx + dy * dy)
const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10
const midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2)
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
// Create new text object if it doesn't exist
const text = new fabric.IText(length.toFixed(0), {
const text = new fabric.Text(length.toFixed(0), {
left: midPoint.x,
top: midPoint.y,
fontSize: this.fontSize,

View File

@ -149,7 +149,7 @@ export default function CanvasMenu(props) {
</div>
}
<div className="btn-from">
<button className="btn01"></button>
<button className="btn01" onClick={() => {}}></button>
<button className="btn02 active"></button>
<button className="btn03 "></button>
</div>

View File

@ -1,12 +1,13 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useState } from 'react'
import { useEffect, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { canvasState, dotLineGridSettingState, dotLineIntervalSelector } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { onlyNumberInputChange } from '@/util/input-utils'
import { fabric } from 'fabric'
import { gridColorState } from '@/store/gridAtom'
import { settingModalGridOptionsState } from '@/store/settingAtom'
const TYPE = {
DOT: 'DOT',
@ -17,6 +18,7 @@ export default function DotLineGrid(props) {
// const [modalOption, setModalOption] = useRecoilState(modalState); //modal state
const [close, setClose] = useState(false)
const { setShowDotLineGridModal } = props
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
const gridColor = useRecoilValue(gridColorState)
const canvas = useRecoilValue(canvasState)
@ -25,6 +27,17 @@ export default function DotLineGrid(props) {
const interval = useRecoilValue(dotLineIntervalSelector)
const { getMessage } = useMessage()
useEffect(() => {
return () => {
setSettingModalGridOptions((prev) => {
const newSettingOptions = [...prev]
newSettingOptions[1].selected = false
return [...newSettingOptions]
})
}
}, [])
const SelectOption = [
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
{ id: 2, name: '1/2', value: 1 / 2 },
@ -144,7 +157,7 @@ export default function DotLineGrid(props) {
const verticalLine = new fabric.Line(
[i * horizontalInterval - horizontalInterval / 2, 0, i * horizontalInterval - horizontalInterval / 2, canvas.height],
{
stroke: 'black',
stroke: gridColor,
strokeWidth: 1,
selectable: true,
lockMovementX: true,

View File

@ -1,14 +1,26 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import ColorPicker from '@/components/common/color-picker/ColorPicker'
import { useRecoilState } from 'recoil'
import { useRecoilState, useSetRecoilState } from 'recoil'
import { gridColorState } from '@/store/gridAtom'
import { useMessage } from '@/hooks/useMessage'
import { useEffect } from 'react'
import { settingModalGridOptionsState } from '@/store/settingAtom'
export default function GridColorSetting(props) {
const { setShowColorPickerModal } = props
const [color, setColor] = useRecoilState(gridColorState)
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
const { getMessage } = useMessage()
useEffect(() => {
return () => {
setSettingModalGridOptions((prev) => {
const newSettingOptions = [...prev]
newSettingOptions[3].selected = false
return [...newSettingOptions]
})
}
}, [])
return (
<WithDraggable isShow={true} pos={{ x: 1300, y: -660 }}>
<div className={`modal-pop-wrap ssm mount`}>

View File

@ -2,6 +2,7 @@
import { useMessage } from '@/hooks/useMessage'
import { onlyNumberInputChange } from '@/util/input-utils'
import GridMove from '@/components/floor-plan/modal/grid/GridMove'
export default function OuterLineWall({ props }) {
const { getMessage } = useMessage()

View File

@ -9,7 +9,7 @@ export default function PropertiesSetting(props) {
const { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } = usePropertiesSetting()
return (
<WithDraggable isShow={true}>
<WithDraggable isShow={true} pos={{ x: 50, y: -950 }}>
<div className={`modal-pop-wrap ssm`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.canvas.setting.wallline.properties.setting')}</h1>

View File

@ -18,7 +18,6 @@ export default function GridOption(props) {
const [color, setColor] = useColor(gridColor)
useEffect(() => {
console.log(color)
setGridColor(color.hex)
}, [color])

View File

@ -6,11 +6,18 @@ import WithDraggable from '@/components/common/draggable/WithDraggable'
import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption'
import { useMessage } from '@/hooks/useMessage'
import GridOption from '@/components/floor-plan/modal/setting01/GridOption'
import { canGridOptionSeletor } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
export default function SettingModal01(props) {
const { setShowCanvasSettingModal, setShowDotLineGridModal, setShowColorPickerModal } = props
const [buttonAct, setButtonAct] = useState(1)
const { getMessage } = useMessage()
const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor)
const handleBtnClick = (num) => {
setButtonAct(num)
}
return (
<WithDraggable isShow={true} pos={{ x: 1300, y: -950 }}>
@ -23,16 +30,18 @@ export default function SettingModal01(props) {
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => setButtonAct(1)}>
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => handleBtnClick(1)}>
{getMessage('modal.canvas.setting.display')}
</button>
<button className={`btn-frame modal ${buttonAct === 2 ? 'act' : ''}`} onClick={() => setButtonAct(2)}>
<button className={`btn-frame modal ${buttonAct === 2 ? 'act' : ''}`} onClick={() => handleBtnClick(2)}>
{getMessage('modal.canvas.setting.font.plan')}
</button>
<button className={`btn-frame modal ${buttonAct === 3 ? 'act' : ''}`} onClick={() => setButtonAct(3)}>
{getMessage('modal.canvas.setting.grid')}
</button>
{canGridOptionSeletorValue && (
<button className={`btn-frame modal ${buttonAct === 3 ? 'act' : ''}`} onClick={() => handleBtnClick(3)}>
{getMessage('modal.canvas.setting.grid')}
</button>
)}
</div>
{buttonAct === 1 && <FirstOption />}
{buttonAct === 2 && <SecondOption />}

View File

@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react'
import { distanceBetweenPoints, getDegreeByChon } from '@/util/canvas-util'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import {
adsorptionPointAddModeState,
adsorptionPointModeState,
@ -20,6 +20,7 @@ import {
outerLineArrow1State,
outerLineArrow2State,
outerLineDiagonalState,
outerLineFixState,
outerLineLength1State,
outerLineLength2State,
outerLinePointsState,
@ -59,6 +60,8 @@ export function useOuterLineWall() {
const arrow1Ref = useRef(arrow1)
const arrow2Ref = useRef(arrow2)
const setOuterLineFix = useSetRecoilState(outerLineFixState)
const outerLineDiagonalLengthRef = useRef(null)
const isFix = useRef(false)
@ -69,6 +72,15 @@ export function useOuterLineWall() {
if (adsorptionPointAddMode || tempGridMode) {
return
}
if (points.length === 0) {
// 만약 포인트가 없다면 모든 라인과 텍스트를 삭제 후 outerLines에서 point를 뽑아 points에 넣어준다.
const lengthTxts = canvas?.getObjects().filter((obj) => obj.name === 'lengthTxt')
lengthTxts.forEach((txt) => {
canvas?.remove(txt)
})
}
addCanvasMouseEventListener('mouse:down', mouseDown)
clear()
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode])
@ -153,6 +165,7 @@ export function useOuterLineWall() {
canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint'))
if (points.length === 0) {
setOuterLineFix(true)
removeAllDocumentEventListeners()
return
}
@ -172,6 +185,7 @@ export function useOuterLineWall() {
canvas?.add(point)
} else {
setOuterLineFix(false)
points.forEach((point, idx) => {
if (idx === 0) {
return
@ -183,10 +197,10 @@ export function useOuterLineWall() {
const firstPoint = points[0]
if (isFix.current) {
canvas?.renderAll()
closeModalFn.current(false)
removeAllMouseEventListeners()
removeAllDocumentEventListeners()
canvas?.renderAll()
closeModalFn.current(false)
}
if (points.length < 3) {

View File

@ -1,91 +1,116 @@
import { useEffect, useRef } from 'react'
import { LINE_TYPE } from '@/common/common'
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useMode } from '@/hooks/useMode'
import { usePolygon } from '@/hooks/usePolygon'
import { useLine } from '@/hooks/useLine'
export function usePropertiesSetting() {
const currentLine = useRef(null)
const currentIdx = useRef(-1)
const canvas = useRecoilValue(canvasState)
const currentObject = useRecoilValue(currentObjectState)
const { drawRoofPolygon } = useMode()
const { addPolygonByLines } = usePolygon()
const { removeLine } = useLine()
useEffect(() => {
selectNextLine()
}, [])
if (!currentObject) {
return
}
if (currentObject.name !== 'outerLine') {
return
}
const type = currentObject.attributes?.type
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
lines.forEach((line) => {
const lineType = line.attributes?.type
if (!lineType) {
line.set({
stroke: '#000000',
strokeWidth: 4,
})
}
})
if (!type) {
currentObject.set({
stroke: '#EA10AC',
strokeWidth: 4,
})
}
}, [currentObject])
const history = useRef([])
const handleSetEaves = () => {
currentLine.current.set({
const selectedLine = canvas?.getActiveObject()
if (!selectedLine) {
return
}
selectedLine.set({
stroke: '#45CD7D',
strokeWidth: 4,
attributes: {
offset: 500,
offset: 50,
type: LINE_TYPE.WALLLINE.EAVES,
pitch: 4,
},
})
history.current.push(selectedLine)
nextLineFocus(selectedLine)
canvas.renderAll()
selectNextLine()
}
const handleSetGable = () => {
currentLine.current.set({
const selectedLine = canvas?.getActiveObject()
if (!selectedLine) {
return
}
selectedLine.set({
stroke: '#3FBAE6',
strokeWidth: 4,
attributes: {
offset: 300,
offset: 30,
type: LINE_TYPE.WALLLINE.GABLE,
},
})
canvas.renderAll()
selectNextLine()
}
const selectNextLine = () => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
currentIdx.current++
if (currentIdx.current >= lines.length) {
currentIdx.current = lines.length
currentLine.current = lines[currentIdx.current - 1]
return
}
currentLine.current = lines[currentIdx.current]
currentLine.current.set({
stroke: '#EA10AC',
strokeWidth: 4,
})
history.current.push(selectedLine)
nextLineFocus(selectedLine)
canvas.renderAll()
}
const selectPrevLine = () => {
const nextLineFocus = (selectedLine) => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const index = lines.findIndex((line) => line === selectedLine)
currentIdx.current--
if (currentIdx.current <= -1) {
currentIdx.current = -1
selectNextLine()
return
const nextLine = lines[index + 1] || lines[0]
if (!nextLine.attributes?.type) {
canvas.setActiveObject(nextLine)
} else {
lines.forEach((line, index) => {
if (index >= currentIdx.current) {
delete line.attributes
line.set({
stroke: '#000000',
strokeWidth: 4,
})
}
currentIdx.current--
canvas.renderAll()
selectNextLine()
})
//activeObject 해제
canvas.discardActiveObject()
}
}
const handleRollback = () => {
selectPrevLine()
if (history.current.length === 0) {
return
}
const lastLine = history.current.pop()
lastLine.set({
stroke: '#000000',
strokeWidth: 4,
})
canvas.setActiveObject(lastLine)
canvas.renderAll()
}
const handleFix = () => {
@ -100,8 +125,15 @@ export function usePropertiesSetting() {
stroke: '#000000',
strokeWidth: 4,
})
removeLine(line)
})
const wall = addPolygonByLines(lines, { name: 'WallLine', fill: 'transparent', stroke: 'black' })
wall.lines = [...lines]
drawRoofPolygon(wall)
canvas.renderAll()
}
@ -121,7 +153,6 @@ export function usePropertiesSetting() {
})
canvas.renderAll()
fn(false)
}

View File

@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState, canvasZoomState, currentMenuState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState, canvasZoomState, currentMenuState, textModeState } from '@/store/canvasAtom'
import { fabric } from 'fabric'
import { calculateDistance, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
@ -12,12 +12,14 @@ export function useEvent() {
const currentMenu = useRecoilValue(currentMenuState)
const documentEventListeners = useRef([])
const mouseEventListeners = useRef([])
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const setCanvasZoom = useSetRecoilState(canvasZoomState)
const { adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, getAdsorptionPoints, adsorptionPointAddModeStateEvent } = useAdsorptionPoint()
const { dotLineGridSetting, interval, getClosestLineGrid } = useDotLineGrid()
const { tempGridModeStateLeftClickEvent, tempGridMode, tempGridRightClickEvent } = useTempGrid()
const textMode = useRecoilValue(textModeState)
useEffect(() => {
if (!canvas) {
return
@ -38,6 +40,7 @@ export function useEvent() {
addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent)
addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent)
addDocumentEventListener('keydown', document, defaultKeyboardEvent)
addDocumentEventListener('contextmenu', document, defaultContextMenuEvent)
if (adsorptionPointAddMode) {
addCanvasMouseEventListener('mouse:down', adsorptionPointAddModeStateEvent)
}

View File

@ -1,5 +1,6 @@
import { useRecoilValue } from 'recoil'
import { canvasState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
export const useLine = () => {
const canvas = useRecoilValue(canvasState)
@ -7,13 +8,13 @@ export const useLine = () => {
const fontFamily = useRecoilValue(fontFamilyState)
const addLine = (points = [], options) => {
const line = new fabric.Line(points, {
const line = new QLine(points, {
...options,
selectable: options.selectable ?? false,
fontSize: fontSize,
fontFamily: fontFamily,
})
canvas?.add(line)
addLineText(line)
return line
}

View File

@ -1678,7 +1678,7 @@ export function useMode() {
const drawRoofPolygon = (wall) => {
// TODO [ljyoung] : offset 입력 처리 후 제거 해야함.
wall.lines.forEach((line, index) => {
/*wall.lines.forEach((line, index) => {
if (index === wall.lines.length - 1 || index === 3) {
line.attributes = {
type: 'gable',
@ -1690,7 +1690,7 @@ export function useMode() {
offset: 50,
}
}
})
})*/
const polygon = createRoofPolygon(wall.points)
const originPolygon = new QPolygon(wall.points, { fontSize: 0 })

View File

@ -2,6 +2,7 @@ import { canvasState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
import { fabric } from 'fabric'
import { getDirectionByPoint } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon'
export const usePolygon = () => {
const canvas = useRecoilValue(canvasState)
@ -9,19 +10,22 @@ export const usePolygon = () => {
const fontFamily = useRecoilValue(fontFamilyState)
const addPolygon = (points, options) => {
const polygon = new fabric.Polygon(points, {
const polygon = new QPolygon(points, {
...options,
selectable: options.selectable ?? false,
fontSize: fontSize,
fontFamily: fontFamily,
selectable: true,
})
canvas?.add(polygon)
addLengthText(polygon)
return polygon
}
const addPolygonByLines = (lines, options) => {
const points = createPolygonPointsFromOuterLines(lines)
addPolygon(points, {
return addPolygon(points, {
...options,
})
}
@ -39,10 +43,11 @@ export const usePolygon = () => {
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
// Create new text object if it doesn't exist
const text = new fabric.IText(length.toString(), {
const text = new fabric.Text(length.toString(), {
left: midPoint.x,
top: midPoint.y,
fontSize: fontSize,
fontFamily: fontFamily,
parentId: polygon.id,
minX: Math.min(start.x, end.x),
maxX: Math.max(start.x, end.x),

View File

@ -1,5 +1,6 @@
import { atom, selector } from 'recoil'
import { MENU } from '@/common/common'
import { outerLineFixState, outerLinePointsState } from '@/store/outerLineAtom'
export const canvasState = atom({
key: 'canvasState',
@ -267,3 +268,18 @@ export const tempGridModeState = atom({
key: 'tempGridModeState',
default: false,
})
export const textModeState = atom({
key: 'textModeState',
default: false,
})
export const canGridOptionSeletor = selector({
key: 'canGridOptionSeletor',
get: ({ get }) => {
const points = get(outerLinePointsState)
const currentMenu = get(currentMenuState)
const outerLineFix = get(outerLineFixState)
return points.length === 0 || outerLineFix
},
})

View File

@ -2,5 +2,5 @@ import { atom } from 'recoil'
export const gridColorState = atom({
key: 'gridColorState',
default: '#000000',
default: '#FF0000',
})

View File

@ -63,3 +63,8 @@ export const outerLinePointsState = atom({
key: 'outerLinePointsState',
default: [],
})
export const outerLineFixState = atom({
key: 'outerLineFixState',
default: false,
})

View File

@ -1,4 +1,4 @@
import { atom } from 'recoil'
import { atom, selector } from 'recoil'
export const settingModalFirstOptionsState = atom({
key: 'settingModalFirstOptions',