This commit is contained in:
hyojun.choi 2024-07-19 19:00:07 +09:00
parent 2f4560c2c9
commit 3d126dbfc7
6 changed files with 158 additions and 101 deletions

View File

@ -7,11 +7,11 @@ import QPolygon from '@/components/fabric/QPolygon'
import RangeSlider from './ui/RangeSlider'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
import { canvasListState, canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine'
export default function Roof2() {
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage } = useCanvas('canvas')
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas, changeCanvas } = useCanvas('canvas')
//canvas
const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
@ -29,6 +29,9 @@ export default function Roof2() {
const [showControl, setShowControl] = useState(false)
const [canvasIdx, setCanvasIdx] = useState(0)
const canvasList = useRecoilValue(canvasListState)
const { mode, changeMode, handleClear, fillCellInPolygon, zoomIn, zoomOut, zoom, togglePolygonLine, handleOuterlinesTest2, applyTemplateB } =
useMode()
@ -180,6 +183,8 @@ export default function Roof2() {
canvas?.add(polygon)
console.log(polygon)
handleOuterlinesTest2(polygon)
// const lines = togglePolygonLine(polygon)
@ -200,17 +205,19 @@ export default function Roof2() {
const makeQLine = () => {
if (canvas) {
const line = new QLine(
[50, 50, 200, 50],
const line = new fabric.QLine(
[200, 200, 500, 500],
{
stroke: 'black',
strokeWidth: 1,
fontSize: fontSize,
selectable: true,
},
50,
)
canvas?.add(line)
console.log(line)
}
}
@ -240,6 +247,12 @@ export default function Roof2() {
setShowControl(!showControl)
}
const nextCanvas = () => {
const nextCanvasNumber = canvasIdx < canvasList.length - 1 ? canvasIdx + 1 : 0
setCanvasIdx(nextCanvasNumber)
changeCanvas(nextCanvasNumber)
}
return (
<>
{canvas && (
@ -333,6 +346,12 @@ export default function Roof2() {
<Button className="m-1 p-2" onClick={PolygonToLine}>
PolygonToLine
</Button>
<Button className="m-1 p-2" onClick={addCanvas}>
캔버스 추가
</Button>
<Button className="m-1 p-2" onClick={nextCanvas}>
다음 캔버스
</Button>
<Button className="m-1 p-2" color={`${showControl ? 'primary' : 'default'}`} onClick={handleShowController}>
canvas 컨트롤러 {`${showControl ? '숨기기' : '보이기'}`}
</Button>

View File

@ -16,7 +16,7 @@ export class QLine extends fabric.Group {
isAlreadyInterSection = false
interSectionPoints = []
#lengthTxt = 0
lengthTxt = 0
constructor(points, option = { isActiveLengthText: true }, lengthTxt) {
// 소수점 전부 제거
@ -44,24 +44,24 @@ export class QLine extends fabric.Group {
this.idx = option.idx
if (lengthTxt > 0) {
this.#lengthTxt = Number(lengthTxt)
this.lengthTxt = Number(lengthTxt)
}
option.isActiveLengthText ?? this.#init()
this.#addControl()
option.isActiveLengthText ?? this.init()
this.addControl()
}
#init() {
this.#addLengthText(true)
init() {
this.addLengthText(true)
}
#addControl() {
addControl() {
this.on('moving', () => {
this.#addLengthText(false)
this.addLengthText(false)
})
this.on('modified', (e) => {
this.#addLengthText(false)
this.addLengthText(false)
})
this.on('selected', () => {
@ -73,19 +73,19 @@ export class QLine extends fabric.Group {
})
}
#addLengthText(isFirst) {
addLengthText(isFirst) {
if (this.text) {
this.removeWithUpdate(this.text)
this.text = null
}
if (isFirst && this.#lengthTxt > 0) {
const text = new fabric.Textbox(this.#lengthTxt.toFixed(0).toString(), {
if (isFirst && this.lengthTxt > 0) {
const text = new fabric.Textbox(this.lengthTxt.toFixed(0).toString(), {
left: (this.x1 + this.x2) / 2,
top: (this.y1 + this.y2) / 2,
fontSize: this.fontSize,
})
this.length = this.#lengthTxt
this.length = this.lengthTxt
this.text = text
this.addWithUpdate(text)
return
@ -115,4 +115,37 @@ export class QLine extends fabric.Group {
this.text.set({ fontSize })
this.addWithUpdate()
}
fromObject(object, callback) {
fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) {
delete object.objects
callback && callback(new fabric.Frindle(enlivenedObjects, object))
})
}
async = true
toObject(propertiesToInclude) {
return fabric.util.object.extend(this.callSuper('toObject'), {
length: this.length,
line: this.line,
text: this.text,
fontSize: this.fontSize,
x1: this.x1,
y1: this.y1,
x2: this.x2,
y2: this.y2,
direction: this.direction,
idx: this.idx,
type: this.type,
parent: this.parent,
isAlreadyInterSection: this.isAlreadyInterSection,
interSectionPoints: this.interSectionPoints,
lengthTxt: this.lengthTxt,
setFontSize: this.setFontSize,
addLengthText: this.addLengthText,
init: this.init,
addControl: this.addControl,
})
}
}

View File

@ -28,6 +28,7 @@ export default class QPolygon extends fabric.Group {
helpLines = []
wall
constructor(points, options, canvas) {
/*if (points.length !== 4 && points.length !== 6) {
throw new Error('Points must be 4 or 6.')
@ -51,13 +52,13 @@ export default class QPolygon extends fabric.Group {
this.points = sortPoints
this.polygon = polygon
this.name = options.name
this.#init()
this.#addEvent()
this.#initLines()
this.init()
this.addEvent()
this.initLines()
this.setShape()
}
#initLines() {
initLines() {
this.points.forEach((point, i) => {
const nextPoint = this.points[(i + 1) % this.points.length]
const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], {
@ -71,13 +72,13 @@ export default class QPolygon extends fabric.Group {
})
}
#init() {
this.#addLengthText()
init() {
this.addLengthText()
}
#addEvent() {
addEvent() {
this.on('scaling', (e) => {
this.#updateLengthText()
this.updateLengthText()
})
this.on('selected', function () {
@ -110,7 +111,7 @@ export default class QPolygon extends fabric.Group {
this.addWithUpdate()
}
#addLengthText() {
addLengthText() {
if (this.texts.length > 0) {
this.texts.forEach((text) => {
this.canvas.remove(text)
@ -142,7 +143,7 @@ export default class QPolygon extends fabric.Group {
this.canvas.renderAll()
}
#updateLengthText() {
updateLengthText() {
const points = this.getCurrentPoints()
points.forEach((start, i) => {
@ -188,7 +189,7 @@ export default class QPolygon extends fabric.Group {
new fabric.Point(rect.left + rect.width, rect.top + rect.height),
]
const isInside = rectPoints.every((rectPoint) => this.inPolygon(rectPoint) && this.#distanceFromEdge(rectPoint) >= cell.padding)
const isInside = rectPoints.every((rectPoint) => this.inPolygon(rectPoint) && this.distanceFromEdge(rectPoint) >= cell.padding)
if (isInside) {
this.addWithUpdate(rect)
@ -245,7 +246,7 @@ export default class QPolygon extends fabric.Group {
return intersects % 2 === 1
}
#distanceFromEdge(point) {
distanceFromEdge(point) {
const vertices = this.getCurrentPoints()
let minDistance = Infinity
@ -317,13 +318,13 @@ export default class QPolygon extends fabric.Group {
}
if (this.lines.length === 4) {
this.#drawHelpLineInRect(chon)
this.drawHelpLineInRect(chon)
} else if (this.lines.length === 6 || this.lines.length === 8) {
// TODO : 6각형
this.#drawHelpLineInHexagon2(chon)
this.drawHelpLineInHexagon2(chon)
} /* else if (this.lines.length === 8) {
// TODO : 8각형
this.#drawHelpLineInOctagon(chon)
this.drawHelpLineInOctagon(chon)
}*/
}
@ -370,7 +371,7 @@ export default class QPolygon extends fabric.Group {
return this.shape
}
#drawHelpLineInRect(chon) {
drawHelpLineInRect(chon) {
let type = 1
let smallestLength = Infinity
let maxLength = 0
@ -526,7 +527,7 @@ export default class QPolygon extends fabric.Group {
this.canvas.add(ridge)
}
}
#drawHelpLineInHexagon2(chon) {
drawHelpLineInHexagon2(chon) {
const oneSideLines = [...this.lines].map((line) => {
let newX1, newY1, newX2, newY2
if (line.direction === 'top') {
@ -742,7 +743,7 @@ export default class QPolygon extends fabric.Group {
this.canvas.renderAll()
})
}
#drawHelpLineInHexagon(chon) {
drawHelpLineInHexagon(chon) {
const historyLines = []
const helpPoints = []
const notInterSectionLines = []
@ -884,5 +885,9 @@ export default class QPolygon extends fabric.Group {
this.canvas.renderAll()
}
#drawHelpLineInOctagon(chon) {}
drawHelpLineInOctagon(chon) {}
getObject() {
return this
}
}

View File

@ -1,13 +1,9 @@
import { useEffect, useRef, useState } from 'react'
import { fabric } from 'fabric'
import {
actionHandler,
anchorWrapper,
polygonPositionHandler,
} from '@/util/canvas-util'
import { actionHandler, anchorWrapper, getDirectionByPoint, polygonPositionHandler, sortedPoints } from '@/util/canvas-util'
import { useRecoilState } from 'recoil'
import { canvasSizeState, fontSizeState } from '@/store/canvasAtom'
import { canvasListState, canvasSizeState, fontSizeState } from '@/store/canvasAtom'
import QPolygon from '@/components/fabric/QPolygon'
import { QLine } from '@/components/fabric/QLine'
import QRect from '@/components/fabric/QRect'
@ -20,6 +16,8 @@ export function useCanvas(id) {
const [fontSize] = useRecoilState(fontSizeState)
const points = useRef([])
const [canvasList, setCanvasList] = useRecoilState(canvasListState)
/**
* 처음 셋팅
*/
@ -31,17 +29,6 @@ export function useCanvas(id) {
selection: false,
})
// settings for all canvas in the app
fabric.Object.prototype.transparentCorners = false
fabric.Object.prototype.cornerColor = '#2BEBC8'
fabric.Object.prototype.cornerStyle = 'rect'
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
fabric.Object.prototype.cornerSize = 6
QPolygon.prototype.canvas = c
QLine.prototype.canvas = c
QRect.prototype.canvas = c
setCanvas(c)
return () => {
c.dispose()
@ -57,24 +44,14 @@ export function useCanvas(id) {
useEffect(() => {
canvas
?.getObjects()
.filter(
(obj) =>
obj.type === 'textbox' ||
obj.type === 'text' ||
obj.type === 'i-text',
)
.filter((obj) => obj.type === 'textbox' || obj.type === 'text' || obj.type === 'i-text')
.forEach((obj) => {
obj.set({ fontSize: fontSize })
})
canvas
?.getObjects()
.filter(
(obj) =>
obj.type === 'QLine' ||
obj.type === 'QPolygon' ||
obj.type === 'QRect',
)
.filter((obj) => obj.type === 'QLine' || obj.type === 'QPolygon' || obj.type === 'QRect')
.forEach((obj) => {
obj.setFontSize(fontSize)
})
@ -121,26 +98,26 @@ export function useCanvas(id) {
*/
const removeMouseLines = () => {
if (canvas?._objects.length > 0) {
const mouseLines = canvas?._objects.filter(
(obj) => obj.name === 'mouseLine',
)
const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine')
mouseLines.forEach((item) => canvas?.remove(item))
}
canvas?.renderAll()
}
/**
* 눈금 그리기
*/
const initialize = () => {
canvas?.clear()
// settings for all canvas in the app
fabric.Object.prototype.transparentCorners = false
fabric.Object.prototype.cornerColor = '#2BEBC8'
fabric.Object.prototype.cornerStyle = 'rect'
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
fabric.Object.prototype.cornerSize = 6
// 기존 이벤트가 있을 경우 제거한다.
// removeEventOnCanvas()
QPolygon.prototype.canvas = canvas
QLine.prototype.canvas = canvas
QRect.prototype.canvas = canvas
// 작업 후에 event를 추가해준다.
// addEventOnCanvas()
fabric.QLine = QLine
}
/**
@ -176,26 +153,20 @@ export function useCanvas(id) {
}
// 가로선을 그립니다.
const horizontalLine = new fabric.Line(
[0, pointer.y, canvasSize.horizontal, pointer.y],
{
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
},
)
const horizontalLine = new fabric.Line([0, pointer.y, canvasSize.horizontal, pointer.y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
})
// 세로선을 그립니다.
const verticalLine = new fabric.Line(
[pointer.x, 0, pointer.x, canvasSize.vertical],
{
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
},
)
const verticalLine = new fabric.Line([pointer.x, 0, pointer.x, canvasSize.vertical], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'mouseLine',
})
// 선들을 캔버스에 추가합니다.
canvas?.add(horizontalLine, verticalLine)
@ -325,7 +296,6 @@ export function useCanvas(id) {
}
const jsonStr = JSON.stringify(canvas)
localStorage.setItem('canvas', jsonStr)
handleClear()
}
/**
@ -479,10 +449,7 @@ export function useCanvas(id) {
poly.controls = poly.points.reduce(function (acc, point, index) {
acc['p' + index] = new fabric.Control({
positionHandler: polygonPositionHandler,
actionHandler: anchorWrapper(
index > 0 ? index - 1 : lastControl,
actionHandler,
),
actionHandler: anchorWrapper(index > 0 ? index - 1 : lastControl, actionHandler),
actionName: 'modifyPolygon',
pointIndex: index,
})
@ -571,6 +538,33 @@ export function useCanvas(id) {
})
}
const addCanvas = () => {
const canvasState = canvas?.getObjects()
canvasState.forEach((state) => {
console.log(state)
})
const str = JSON.stringify(canvasState)
canvas?.clear()
JSON.parse(str).forEach((state) => {
canvas?.add(state)
})
/*const stateArr = canvasState.map((state) => state.getObject().getObjects())
const newCanvasList = [...canvasList, JSON.stringify(stateArr)]
setCanvasList(newCanvasList)*/
}
const changeCanvas = (idx) => {
canvas?.clear()
const canvasState = JSON.parse(canvasList[idx])
}
return {
canvas,
addShape,
@ -585,5 +579,7 @@ export function useCanvas(id) {
saveImage,
handleFlip,
setCanvasBackgroundWithDots,
addCanvas,
changeCanvas,
}
}

View File

@ -718,8 +718,6 @@ export function useMode() {
const handleOuterlinesTest = (polygon, offset = 71) => {
var offsetPoints = []
debugger
const sortedIndex = getStartIndex(polygon.lines)
let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex)

View File

@ -35,3 +35,9 @@ export const wallState = atom({
default: {},
dangerouslyAllowMutability: true,
})
export const canvasListState = atom({
key: 'canvas',
default: [],
dangerouslyAllowMutability: true,
})