mode 관련 추가
This commit is contained in:
parent
f28b183c01
commit
b2821c6081
171
src/app/mode.js
Normal file
171
src/app/mode.js
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
import { useRef, useState } from 'react'
|
||||||
|
|
||||||
|
export function useMode() {
|
||||||
|
const [mode, setMode] = useState(MODE.EDIT)
|
||||||
|
const points = useRef([])
|
||||||
|
|
||||||
|
const addEvent = (canvas, mode) => {
|
||||||
|
switch (mode) {
|
||||||
|
case 'edit':
|
||||||
|
editMode(canvas)
|
||||||
|
break
|
||||||
|
case 'template':
|
||||||
|
templateMode(canvas)
|
||||||
|
break
|
||||||
|
case 'textbox':
|
||||||
|
textboxMode(canvas)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeMode = (canvas, mode) => {
|
||||||
|
setMode(mode)
|
||||||
|
// mode변경 시 이전 이벤트 제거
|
||||||
|
canvas?.off('mouse:down')
|
||||||
|
|
||||||
|
addEvent(canvas, mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
const editMode = (canvas) => {
|
||||||
|
canvas?.on('mouse:down', function (options) {
|
||||||
|
const pointer = canvas?.getPointer(options.e)
|
||||||
|
const circle = new fabric.Circle({
|
||||||
|
radius: 5,
|
||||||
|
fill: 'transparent', // 원 안을 비웁니다.
|
||||||
|
stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
|
||||||
|
left: pointer.x,
|
||||||
|
top: pointer.y,
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
selectable: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
points.current.push(circle)
|
||||||
|
canvas?.add(circle)
|
||||||
|
|
||||||
|
if (points.current.length === 2) {
|
||||||
|
const length = Number(prompt('길이를 입력하세요:'))
|
||||||
|
// length 값이 숫자가 아닌 경우
|
||||||
|
if (isNaN(length) || length === 0) {
|
||||||
|
// 기존에 추가된 circle과 pointer를 제거합니다.
|
||||||
|
points.current.forEach((point) => {
|
||||||
|
canvas?.remove(point)
|
||||||
|
})
|
||||||
|
points.current = []
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length) {
|
||||||
|
const vector = {
|
||||||
|
x: points.current[1].left - points.current[0].left,
|
||||||
|
y: points.current[1].top - points.current[0].top,
|
||||||
|
}
|
||||||
|
const slope = Math.abs(vector.y / vector.x) // 기울기 계산
|
||||||
|
|
||||||
|
let scaledVector
|
||||||
|
if (slope >= 1) {
|
||||||
|
// 기울기가 1 이상이면 x축 방향으로 그림
|
||||||
|
scaledVector = {
|
||||||
|
x: 0,
|
||||||
|
y: vector.y >= 0 ? Number(length) : -Number(length),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 기울기가 1 미만이면 y축 방향으로 그림
|
||||||
|
scaledVector = {
|
||||||
|
x: vector.x >= 0 ? Number(length) : -Number(length),
|
||||||
|
y: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let direction
|
||||||
|
if (Math.abs(vector.x) > Math.abs(vector.y)) {
|
||||||
|
// x축 방향으로 더 많이 이동
|
||||||
|
direction = vector.x > 0 ? 'right' : 'left'
|
||||||
|
} else {
|
||||||
|
// y축 방향으로 더 많이 이동
|
||||||
|
direction = vector.y > 0 ? 'bottom' : 'top'
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = new fabric.Line(
|
||||||
|
[
|
||||||
|
points.current[0].left,
|
||||||
|
points.current[0].top,
|
||||||
|
points.current[0].left + scaledVector.x,
|
||||||
|
points.current[0].top + scaledVector.y,
|
||||||
|
],
|
||||||
|
{
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
selectable: false,
|
||||||
|
direction: direction,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
const text = new fabric.Text(length.toString(), {
|
||||||
|
left:
|
||||||
|
(points.current[0].left +
|
||||||
|
points.current[0].left +
|
||||||
|
scaledVector.x) /
|
||||||
|
2,
|
||||||
|
top:
|
||||||
|
(points.current[0].top + points.current[0].top + scaledVector.y) /
|
||||||
|
2,
|
||||||
|
fontSize: 15,
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
selectable: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 라인의 끝에 점을 추가합니다.
|
||||||
|
const endPointCircle = new fabric.Circle({
|
||||||
|
radius: 5,
|
||||||
|
fill: 'transparent', // 원 안을 비웁니다.
|
||||||
|
stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
|
||||||
|
left: points.current[0].left + scaledVector.x,
|
||||||
|
top: points.current[0].top + scaledVector.y,
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
selectable: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(line)
|
||||||
|
canvas?.add(text)
|
||||||
|
canvas?.add(endPointCircle)
|
||||||
|
points.current.forEach((point) => {
|
||||||
|
canvas?.remove(point)
|
||||||
|
})
|
||||||
|
points.current = [endPointCircle]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateMode = (canvas) => {}
|
||||||
|
|
||||||
|
const textboxMode = (canvas) => {
|
||||||
|
canvas?.on('mouse:down', function (options) {
|
||||||
|
const pointer = canvas?.getPointer(options.e)
|
||||||
|
|
||||||
|
const textbox = new fabric.Textbox('텍스트를 입력하세요', {
|
||||||
|
left: pointer.x,
|
||||||
|
top: pointer.y,
|
||||||
|
width: 150, // 텍스트박스의 너비를 설정합니다.
|
||||||
|
fontSize: 16, // 텍스트의 크기를 설정합니다.
|
||||||
|
})
|
||||||
|
|
||||||
|
canvas?.add(textbox)
|
||||||
|
canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다.
|
||||||
|
canvas?.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return { mode, changeMode }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MODE = {
|
||||||
|
EDIT: 'edit',
|
||||||
|
TEMPLATE: 'template',
|
||||||
|
TEXTBOX: 'textbox',
|
||||||
|
}
|
||||||
@ -1,135 +1,38 @@
|
|||||||
import { useCanvas } from '@/hooks/useCanvas'
|
import { useCanvas } from '@/hooks/useCanvas'
|
||||||
import { useEffect, useRef } from 'react'
|
import { useEffect } from 'react'
|
||||||
|
import { MODE, useMode } from '@/app/mode'
|
||||||
|
|
||||||
export default function Roof2() {
|
export default function Roof2() {
|
||||||
const { canvas } = useCanvas('canvas')
|
const { canvas } = useCanvas('canvas')
|
||||||
const mode = useRef('')
|
|
||||||
const points = useRef([])
|
const { mode, changeMode } = useMode()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
canvas?.on('mouse:down', function (options) {
|
// canvas가 없는 경우
|
||||||
const pointer = canvas?.getPointer(options.e)
|
if (!canvas) return
|
||||||
const circle = new fabric.Circle({
|
// canvas가 있는 경우
|
||||||
radius: 5,
|
changeMode(canvas, mode)
|
||||||
fill: 'transparent', // 원 안을 비웁니다.
|
}, [mode])
|
||||||
stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
|
|
||||||
left: pointer.x,
|
|
||||||
top: pointer.y,
|
|
||||||
originX: 'center',
|
|
||||||
originY: 'center',
|
|
||||||
selectable: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
points.current.push(circle)
|
|
||||||
canvas?.add(circle)
|
|
||||||
|
|
||||||
if (points.current.length === 2) {
|
|
||||||
const length = Number(prompt('길이를 입력하세요:'))
|
|
||||||
// length 값이 숫자가 아닌 경우
|
|
||||||
if (isNaN(length) || length === 0) {
|
|
||||||
// 기존에 추가된 circle과 pointer를 제거합니다.
|
|
||||||
points.current.forEach((point) => {
|
|
||||||
canvas?.remove(point)
|
|
||||||
})
|
|
||||||
points.current = []
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length) {
|
|
||||||
const vector = {
|
|
||||||
x: points.current[1].left - points.current[0].left,
|
|
||||||
y: points.current[1].top - points.current[0].top,
|
|
||||||
}
|
|
||||||
const slope = Math.abs(vector.y / vector.x) // 기울기 계산
|
|
||||||
|
|
||||||
let scaledVector
|
|
||||||
if (slope >= 1) {
|
|
||||||
// 기울기가 1 이상이면 x축 방향으로 그림
|
|
||||||
scaledVector = {
|
|
||||||
x: 0,
|
|
||||||
y: vector.y >= 0 ? Number(length) : -Number(length),
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 기울기가 1 미만이면 y축 방향으로 그림
|
|
||||||
scaledVector = {
|
|
||||||
x: vector.x >= 0 ? Number(length) : -Number(length),
|
|
||||||
y: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let direction
|
|
||||||
if (Math.abs(vector.x) > Math.abs(vector.y)) {
|
|
||||||
// x축 방향으로 더 많이 이동
|
|
||||||
direction = vector.x > 0 ? 'right' : 'left'
|
|
||||||
} else {
|
|
||||||
// y축 방향으로 더 많이 이동
|
|
||||||
direction = vector.y > 0 ? 'bottom' : 'top'
|
|
||||||
}
|
|
||||||
|
|
||||||
const line = new fabric.Line(
|
|
||||||
[
|
|
||||||
points.current[0].left,
|
|
||||||
points.current[0].top,
|
|
||||||
points.current[0].left + scaledVector.x,
|
|
||||||
points.current[0].top + scaledVector.y,
|
|
||||||
],
|
|
||||||
{
|
|
||||||
stroke: 'black',
|
|
||||||
strokeWidth: 2,
|
|
||||||
selectable: false,
|
|
||||||
direction: direction,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
const text = new fabric.Text(length.toString(), {
|
|
||||||
left:
|
|
||||||
(points.current[0].left +
|
|
||||||
points.current[0].left +
|
|
||||||
scaledVector.x) /
|
|
||||||
2,
|
|
||||||
top:
|
|
||||||
(points.current[0].top + points.current[0].top + scaledVector.y) /
|
|
||||||
2,
|
|
||||||
fontSize: 15,
|
|
||||||
originX: 'center',
|
|
||||||
originY: 'center',
|
|
||||||
selectable: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
// 라인의 끝에 점을 추가합니다.
|
|
||||||
const endPointCircle = new fabric.Circle({
|
|
||||||
radius: 5,
|
|
||||||
fill: 'transparent', // 원 안을 비웁니다.
|
|
||||||
stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다.
|
|
||||||
left: points.current[0].left + scaledVector.x,
|
|
||||||
top: points.current[0].top + scaledVector.y,
|
|
||||||
originX: 'center',
|
|
||||||
originY: 'center',
|
|
||||||
selectable: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas?.add(line)
|
|
||||||
canvas?.add(text)
|
|
||||||
canvas?.add(endPointCircle)
|
|
||||||
points.current.forEach((point) => {
|
|
||||||
canvas?.remove(point)
|
|
||||||
})
|
|
||||||
points.current = [endPointCircle]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas?.renderAll()
|
|
||||||
})
|
|
||||||
}, [canvas])
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="flex justify-center my-8">
|
<div className="flex justify-center my-8">
|
||||||
<button className="w-30 mx-2 p-2 rounded bg-blue-500 text-white">
|
<button
|
||||||
|
className={`w-30 mx-2 p-2 rounded ${mode === MODE.EDIT ? 'bg-blue-500' : 'bg-gray-500'} text-white`}
|
||||||
|
onClick={() => changeMode(canvas, MODE.EDIT)}
|
||||||
|
>
|
||||||
Editing
|
Editing
|
||||||
</button>
|
</button>
|
||||||
<button className="w-30 mx-2 p-2 rounded bg-gray-500 text-white">
|
<button
|
||||||
|
className={`w-30 mx-2 p-2 rounded ${mode === MODE.TEMPLATE ? 'bg-blue-500' : 'bg-gray-500'} text-white`}
|
||||||
|
onClick={() => changeMode(canvas, MODE.TEMPLATE)}
|
||||||
|
>
|
||||||
Template
|
Template
|
||||||
</button>
|
</button>
|
||||||
<button className="w-30 mx-2 p-2 rounded bg-gray-500 text-white">
|
<button
|
||||||
|
className={`w-30 mx-2 p-2 rounded ${mode === MODE.TEXTBOX ? 'bg-blue-500' : 'bg-gray-500'} text-white`}
|
||||||
|
onClick={() => changeMode(canvas, MODE.TEXTBOX)}
|
||||||
|
>
|
||||||
텍스트박스 mode
|
텍스트박스 mode
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user