가이드 라인 추가
This commit is contained in:
parent
b9601e4fbb
commit
a9ee0bc08c
@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
import { useCanvas } from '@/hooks/useCanvas'
|
import { useCanvas } from '@/hooks/useCanvas'
|
||||||
import { useEffect, useState, useRef } from 'react'
|
import { useEffect, useState, useRef } from 'react'
|
||||||
import { Mode, useMode } from '@/hooks/useMode'
|
import { useMode } from '@/hooks/useMode'
|
||||||
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
|
import { Mode } from '@/common/common'
|
||||||
|
import { Button } from '@nextui-org/react'
|
||||||
import RangeSlider from './ui/RangeSlider'
|
import RangeSlider from './ui/RangeSlider'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import {
|
import {
|
||||||
@ -21,7 +22,6 @@ import { getCanvasState, insertCanvasState } from '@/lib/canvas'
|
|||||||
import { calculateIntersection } from '@/util/canvas-util'
|
import { calculateIntersection } from '@/util/canvas-util'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import ThumbnailList from './ui/ThumbnailLIst'
|
import ThumbnailList from './ui/ThumbnailLIst'
|
||||||
// import CanvasWithContextMenu from '@/util/context-util'
|
|
||||||
import QContextMenu from './common/context-menu/QContextMenu'
|
import QContextMenu from './common/context-menu/QContextMenu'
|
||||||
import { modalContent, modalState } from '@/store/modalAtom'
|
import { modalContent, modalState } from '@/store/modalAtom'
|
||||||
import SettingsModal from './SettingsModal'
|
import SettingsModal from './SettingsModal'
|
||||||
@ -61,12 +61,6 @@ export default function Roof2() {
|
|||||||
const [open, setOpen] = useRecoilState(modalState)
|
const [open, setOpen] = useRecoilState(modalState)
|
||||||
const [contents, setContent] = useRecoilState(modalContent)
|
const [contents, setContent] = useRecoilState(modalContent)
|
||||||
|
|
||||||
// const gridHandleClick = (e) => {
|
|
||||||
// console.log(e !== 'custom')
|
|
||||||
|
|
||||||
// setIsCustomGridSetting(e !== 'custom')
|
|
||||||
// }
|
|
||||||
|
|
||||||
//canvas 썸네일
|
//canvas 썸네일
|
||||||
const [thumbnails, setThumbnails] = useState([])
|
const [thumbnails, setThumbnails] = useState([])
|
||||||
const thumbnailProps = {
|
const thumbnailProps = {
|
||||||
@ -544,9 +538,8 @@ export default function Roof2() {
|
|||||||
<div className=" my-8 w-full text:pretty">
|
<div className=" my-8 w-full text:pretty">
|
||||||
<Button
|
<Button
|
||||||
className="m-1 p-2"
|
className="m-1 p-2"
|
||||||
color={`${mode === Mode.DEFAULT ? 'primary' : 'default'}`}
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setContent(<SettingsModal />)
|
setContent(<SettingsModal canvasProps={canvas} />)
|
||||||
setOpen(true)
|
setOpen(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,56 +1,259 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useRef, useState } from 'react'
|
||||||
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
|
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import { modalContent, modalState } from '@/store/modalAtom'
|
||||||
|
import { fabric } from 'fabric'
|
||||||
|
|
||||||
export default function SettingsModal() {
|
export default function SettingsModal(props) {
|
||||||
|
const { canvasProps } = props
|
||||||
const [isCustomGridSetting, setIsCustomGridSetting] = useState(true)
|
const [isCustomGridSetting, setIsCustomGridSetting] = useState(true)
|
||||||
|
const [gridCheckedValue, setGridCheckValue] = useState([])
|
||||||
const [ratioValue, setRatioValue] = useState('원치수')
|
const [ratioValue, setRatioValue] = useState('원치수')
|
||||||
|
const moduleLength = useRef(90) //모듈 mm 길이 입력
|
||||||
|
|
||||||
|
const [open, setOpen] = useRecoilState(modalState)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsCustomGridSetting(ratioValue !== 'custom')
|
setIsCustomGridSetting(ratioValue !== 'custom')
|
||||||
}, [ratioValue])
|
}, [ratioValue])
|
||||||
|
|
||||||
|
const drawGridSettings = () => {
|
||||||
|
if (gridCheckedValue.includes('line')) {
|
||||||
|
// fabric.GuideRect = fabric.util.createClass(fabric.Rect, {
|
||||||
|
// _render: function (ctx) {
|
||||||
|
// this.callSuper('_render', ctx)
|
||||||
|
// ctx.strokeStyle = this.stroke || 'blue'
|
||||||
|
// ctx.lineWidth = this.strokeWidth || 1
|
||||||
|
|
||||||
|
// ctx.beginPath()
|
||||||
|
// ctx.moveTo(-this.width / 2, -this.height / 2)
|
||||||
|
// ctx.lineTo(this.width / 2, -this.height / 2)
|
||||||
|
// ctx.lineTo(this.width / 2, this.height / 2)
|
||||||
|
// ctx.stroke()
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
|
||||||
|
// const guideRect = new fabric.GuideRect({
|
||||||
|
// width: canvasProps.width,
|
||||||
|
// height: canvasProps.height,
|
||||||
|
// stroke: 'blue',
|
||||||
|
// strokeWidth: 1,
|
||||||
|
// selectable: false,
|
||||||
|
// fill: 'transparent',
|
||||||
|
// name: 'guideRect',
|
||||||
|
// })
|
||||||
|
|
||||||
|
// const patternSourceCanvas = new fabric.StaticCanvas(null, {
|
||||||
|
// width: moduleLength.current.value,
|
||||||
|
// height: moduleLength.current.value,
|
||||||
|
// backgroundColor: 'white',
|
||||||
|
// })
|
||||||
|
|
||||||
|
// patternSourceCanvas.add(guideRect)
|
||||||
|
// patternSourceCanvas.renderAll()
|
||||||
|
|
||||||
|
// const pattern = new fabric.Pattern({
|
||||||
|
// source: patternSourceCanvas.getElement(),
|
||||||
|
// repeat: 'repeat',
|
||||||
|
// })
|
||||||
|
|
||||||
|
const horizontalLineArray = []
|
||||||
|
const verticalLineArray = []
|
||||||
|
|
||||||
|
for (let i = 0; i < canvasProps.height / moduleLength.current.value + 1; i++) {
|
||||||
|
const horizontalLine = new fabric.Line(
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
i * moduleLength.current.value - moduleLength.current.value / 2,
|
||||||
|
canvasProps.width,
|
||||||
|
i * moduleLength.current.value - moduleLength.current.value / 2,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
stroke: 'gray',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'guideLine',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
canvasProps.add(horizontalLine)
|
||||||
|
horizontalLineArray.push(horizontalLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < canvasProps.width / moduleLength.current.value + 1; i++) {
|
||||||
|
const verticalLine = new fabric.Line(
|
||||||
|
[
|
||||||
|
i * moduleLength.current.value - moduleLength.current.value / 2,
|
||||||
|
0,
|
||||||
|
i * moduleLength.current.value - moduleLength.current.value / 2,
|
||||||
|
canvasProps.height,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
stroke: 'gray',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'guideLine',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
canvasProps.add(verticalLine)
|
||||||
|
verticalLineArray.push(verticalLine)
|
||||||
|
}
|
||||||
|
canvasProps.renderAll()
|
||||||
|
const snapDistance = 10
|
||||||
|
|
||||||
|
console.log('horizontalLineArray', horizontalLineArray)
|
||||||
|
|
||||||
|
canvasProps.on('mouse:move', function (e) {
|
||||||
|
let mouseObj = e
|
||||||
|
const mouseCursorX = e.pointer.x
|
||||||
|
const mouseCursorY = e.pointer.y
|
||||||
|
|
||||||
|
console.log(`mouseCursorX : ${mouseCursorX}, mouseCursorY : ${mouseCursorY}`)
|
||||||
|
|
||||||
|
horizontalLineArray.forEach((line) => {
|
||||||
|
console.log()
|
||||||
|
|
||||||
|
if (Math.abs(mouseCursorY - line.y1) < snapDistance) {
|
||||||
|
mouseObj.x = mouseCursorX
|
||||||
|
mouseObj.y = line.y1
|
||||||
|
}
|
||||||
|
// if (Math.abs(mouseCursorX - line.x2) < snapDistance) {
|
||||||
|
// line.set({ x2: mouseCursorX })
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// canvasProps.on('mouse:move', (e) => {
|
||||||
|
// console.log('event', e.pointer)
|
||||||
|
|
||||||
|
// const obj = e
|
||||||
|
|
||||||
|
// if (!obj) return
|
||||||
|
|
||||||
|
// canvasProps.forEachObject(function (target) {
|
||||||
|
// if (target.name === 'guideLine' || target.name === 'guideDot') {
|
||||||
|
// console.log('line : ', target)
|
||||||
|
|
||||||
|
// const lineStartX = target.x1,
|
||||||
|
// lineStartY = target.y1
|
||||||
|
// const lineEndX = target.x2,
|
||||||
|
// lineEndY = target.y2
|
||||||
|
|
||||||
|
// console.log('target.x1', target.x1)
|
||||||
|
// console.log('target.y1', target.y1)
|
||||||
|
// console.log(`obj.pointer.y : ${obj.pointer.y}, obj.pointer.x : ${obj.pointer.x}`)
|
||||||
|
|
||||||
|
// // 수평 선에 대한 스냅
|
||||||
|
// if (Math.abs(obj.pointer.y - lineStartY) < snapDistance) {
|
||||||
|
// obj.pointer.y = lineStartY
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 수직 선에 대한 스냅
|
||||||
|
// if (Math.abs(obj.pointer.x - lineStartX) < snapDistance) {
|
||||||
|
// obj.pointer.x = lineStartX
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gridCheckedValue.includes('dot')) {
|
||||||
|
const circle = new fabric.Circle({
|
||||||
|
radius: 5,
|
||||||
|
fill: 'red',
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
selectable: false,
|
||||||
|
lockMovementX: true,
|
||||||
|
lockMovementY: true,
|
||||||
|
lockRotation: true,
|
||||||
|
lockScalingX: true,
|
||||||
|
lockScalingY: true,
|
||||||
|
name: 'guideDot',
|
||||||
|
})
|
||||||
|
|
||||||
|
const patternSourceCanvas = new fabric.StaticCanvas(null, {
|
||||||
|
width: moduleLength.current.value,
|
||||||
|
height: moduleLength.current.value,
|
||||||
|
})
|
||||||
|
|
||||||
|
patternSourceCanvas.add(circle)
|
||||||
|
|
||||||
|
circle.set({
|
||||||
|
left: patternSourceCanvas.width / 2,
|
||||||
|
top: patternSourceCanvas.height / 2,
|
||||||
|
})
|
||||||
|
|
||||||
|
patternSourceCanvas.renderAll()
|
||||||
|
|
||||||
|
const pattern = new fabric.Pattern({
|
||||||
|
source: patternSourceCanvas.getElement(),
|
||||||
|
repeat: 'repeat',
|
||||||
|
})
|
||||||
|
|
||||||
|
const backgroundPolygon = new fabric.Polygon(
|
||||||
|
[
|
||||||
|
{ x: 0, y: 0 },
|
||||||
|
{ x: canvasProps.width, y: 0 },
|
||||||
|
{ x: canvasProps.width, y: canvasProps.height },
|
||||||
|
{ x: 0, y: canvasProps.height },
|
||||||
|
],
|
||||||
|
{
|
||||||
|
fill: pattern,
|
||||||
|
selectable: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
canvasProps.add(backgroundPolygon)
|
||||||
|
canvasProps.renderAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
canvasProps.renderAll()
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
<div>
|
||||||
<h3 style={{ margin: '0', fontSize: '16px', marginBottom: '10px' }}>점 그리드 설정</h3>
|
|
||||||
<label style={{ display: 'block', marginBottom: '5px' }}>
|
|
||||||
<CheckboxGroup label="그리드 설정" defaultValue={[]}>
|
|
||||||
<Checkbox value="dot">점 그리드</Checkbox>
|
|
||||||
<Checkbox value="line">점선 그리드</Checkbox>
|
|
||||||
</CheckboxGroup>
|
|
||||||
</label>
|
|
||||||
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||||
<Input type="number" label="모듈" />
|
<label style={{ display: 'block', marginBottom: '5px' }}>
|
||||||
|
<CheckboxGroup label="그리드 설정" value={gridCheckedValue} onValueChange={setGridCheckValue}>
|
||||||
|
<Checkbox value="dot">점 그리드</Checkbox>
|
||||||
|
<Checkbox value="line">점선 그리드</Checkbox>
|
||||||
|
</CheckboxGroup>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||||
|
<Input type="number" label="모듈" ref={moduleLength} defaultValue="90" />
|
||||||
mm
|
mm
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||||
<p className="text-default-500 text-small">Selected: {ratioValue}</p>
|
<RadioGroup label="비율 설정" onValueChange={setRatioValue}>
|
||||||
|
<Radio value="원치수">원치수</Radio>
|
||||||
<RadioGroup label="비율 설정" onValueChange={setRatioValue}>
|
<Radio value="1/2">1/2</Radio>
|
||||||
<Radio value="원치수">원치수</Radio>
|
<Radio value="1/4">1/4</Radio>
|
||||||
<Radio value="1/2">1/2</Radio>
|
<Radio value="1/10">1/10</Radio>
|
||||||
<Radio value="1/4">1/4</Radio>
|
<Radio value="custom">임의간격</Radio>
|
||||||
<Radio value="1/10">1/10</Radio>
|
</RadioGroup>
|
||||||
<Radio value="custom">임의간격</Radio>
|
</div>
|
||||||
</RadioGroup>
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4"></div>
|
||||||
<Checkbox value="linked" isDisabled={isCustomGridSetting}>
|
<Checkbox value="linked" isDisabled={isCustomGridSetting}>
|
||||||
종횡연동
|
종횡연동
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
</div>
|
||||||
<Input type="number" label="가로간격" min={0} isDisabled={isCustomGridSetting} />
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||||
mm
|
<Input type="number" label="가로간격" min={0} isDisabled={isCustomGridSetting} />
|
||||||
</div>
|
mm
|
||||||
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
</div>
|
||||||
<Input type="number" label="세로간격" min={0} isDisabled={isCustomGridSetting} />
|
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
||||||
mm
|
<Input type="number" label="세로간격" min={0} isDisabled={isCustomGridSetting} />
|
||||||
</div>
|
mm
|
||||||
<div className="flex gap-4 items-center">
|
</div>
|
||||||
<Button size="sm">초기화</Button>
|
<div className="flex gap-4 items-center">
|
||||||
<Button size="sm" color="secondary">
|
<Button size="sm">초기화</Button>
|
||||||
저장
|
<Button size="sm" color="secondary" onClick={drawGridSettings} isDisabled={gridCheckedValue.length === 0}>
|
||||||
</Button>
|
저장
|
||||||
<Button size="sm">취소</Button>
|
</Button>
|
||||||
</div>
|
<Button size="sm" onClick={() => setOpen(!open)}>
|
||||||
|
취소
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -67,7 +67,7 @@ export function useMode() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 이벤트 리스너 추가
|
// 이벤트 리스너 추가
|
||||||
// if (!canvas) {
|
// if (!canvas) {
|
||||||
canvas?.setZoom(0.8)
|
// canvas?.setZoom(0.8)
|
||||||
// return
|
// return
|
||||||
// }
|
// }
|
||||||
document.addEventListener('keydown', handleKeyDown)
|
document.addEventListener('keydown', handleKeyDown)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user