QPolygon2
This commit is contained in:
parent
0ba9b9a4e2
commit
1cc33450ef
@ -12,4 +12,4 @@
|
|||||||
<img src="https://d3i5xzrs7pdkv5.cloudfront.net/4980601633684579445/files/blobs/sha512/893b/893b1d1026d6ffdd7fcaf6db726ebc4cab15688c9d0235ff5b293f91a8b709b0f5f9ffa0f806402486a172270dca79ecdb45a43eab7cdebf4d1649b3e0b438e3?Expires=1720073686&Signature=xn2JzdYtlN4cl834356FuNBRx~oeyxDxd27arM7NMcno11eCNc6~whfmY8issioG6jQKme4JeXQsG9DnbEgBw62751dJuUZWnZ9V4f1F38LjfKiH1VNrqJrTuEw~zDmEcA7kGCYcLRwdEAS1cVe7a7pSU8L9jBrJJewxPcogZ9pN-U6LIaBdd1ImPJV1UwcAEoi-ZubUGYcS-VqqnohDo8gDs2Lb3B7Ovc5Jxa5jwgx9TOPTlOnioupGr5tlmeU~0WfCatDxTOUZPpiBtJYbNGbaTRlfwlNcKQIB5PvT6-YYbhg8x6dv8qpC-vUfkq0xMtLHTrkpL8w83SrCGbLRqQ__&Key-Pair-Id=APKAIBRFJQGZXNBTFYIA">
|
<img src="https://d3i5xzrs7pdkv5.cloudfront.net/4980601633684579445/files/blobs/sha512/893b/893b1d1026d6ffdd7fcaf6db726ebc4cab15688c9d0235ff5b293f91a8b709b0f5f9ffa0f806402486a172270dca79ecdb45a43eab7cdebf4d1649b3e0b438e3?Expires=1720073686&Signature=xn2JzdYtlN4cl834356FuNBRx~oeyxDxd27arM7NMcno11eCNc6~whfmY8issioG6jQKme4JeXQsG9DnbEgBw62751dJuUZWnZ9V4f1F38LjfKiH1VNrqJrTuEw~zDmEcA7kGCYcLRwdEAS1cVe7a7pSU8L9jBrJJewxPcogZ9pN-U6LIaBdd1ImPJV1UwcAEoi-ZubUGYcS-VqqnohDo8gDs2Lb3B7Ovc5Jxa5jwgx9TOPTlOnioupGr5tlmeU~0WfCatDxTOUZPpiBtJYbNGbaTRlfwlNcKQIB5PvT6-YYbhg8x6dv8qpC-vUfkq0xMtLHTrkpL8w83SrCGbLRqQ__&Key-Pair-Id=APKAIBRFJQGZXNBTFYIA">
|
||||||
|
|
||||||
### type4
|
### type4
|
||||||
<img src="https://d3i5xzrs7pdkv5.cloudfront.net/4980601633684579445/files/blobs/sha512/e457/e457b1d5bb8dfd7d579068d5f3f986ae1ee0cd2f10f45f97f39474a35d959e1f7fd4f88370613088a0a1531cddce3e556eae982ea7bea15f19f3ff1f4239f2dc?Expires=1720073695&Signature=hbHtO6NMA-F8UzhHM5y6Y0KkBY9he-9~5kVUgkOn3phXql4I0hyHiaKH6rFKejIYMZHPtuUmPutLNGZjxDfhVJnljvZ157qtdUpHe9nCgl~i7j87djhALHVoEhmdi7CxLbiP236kbMFSPwZ1CnmqGNaJ5P1J8TLAsT~EU7YUODF-5P5tp7PSLZUcTwbwvZ6zwivt0TQDCmGcMOeRYc7EWx1Vl2vfpbOYMZaHvKKn4DCP~qjyDPv5L84v1P9SeFWB5NgDxJhESTSa3NhVxQC4ngq5MGMgeBo3n6ZykCkBeEhvgYeQLHZUoDykNS3a8Fk2H1BbKBViqqKskR8m11xDXQ__&Key-Pair-Id=APKAIBRFJQGZXNBTFYIA">
|
<img src="https://d3i5xzrs7pdkv5.cloudfront.net/498060163368457944ㅈ5/files/blobs/sha512/e457/e457b1d5bb8dfd7d579068d5f3f986ae1ee0cd2f10f45f97f39474a35d959e1f7fd4f88370613088a0a1531cddce3e556eae982ea7bea15f19f3ff1f4239f2dc?Expires=1720073695&Signature=hbHtO6NMA-F8UzhHM5y6Y0KkBY9he-9~5kVUgkOn3phXql4I0hyHiaKH6rFKejIYMZHPtuUmPutLNGZjxDfhVJnljvZ157qtdUpHe9nCgl~i7j87djhALHVoEhmdi7CxLbiP236kbMFSPwZ1CnmqGNaJ5P1J8TLAsT~EU7YUODF-5P5tp7PSLZUcTwbwvZ6zwivt0TQDCmGcMOeRYc7EWx1Vl2vfpbOYMZaHvKKn4DCP~qjyDPv5L84v1P9SeFWB5NgDxJhESTSa3NhVxQC4ngq5MGMgeBo3n6ZykCkBeEhvgYeQLHZUoDykNS3a8Fk2H1BbKBViqqKskR8m11xDXQ__&Key-Pair-Id=APKAIBRFJQGZXNBTFYIA">
|
||||||
@ -4,13 +4,19 @@ import { Mode, useMode } from '@/hooks/useMode'
|
|||||||
import QRect from '@/components/fabric/QRect'
|
import QRect from '@/components/fabric/QRect'
|
||||||
import QLine from '@/components/fabric/QLine'
|
import QLine from '@/components/fabric/QLine'
|
||||||
import QPolygon from '@/components/fabric/QPolygon'
|
import QPolygon from '@/components/fabric/QPolygon'
|
||||||
|
import QPolygon2 from '@/components/fabric/QPolygon2'
|
||||||
import RangeSlider from './ui/RangeSlider'
|
import RangeSlider from './ui/RangeSlider'
|
||||||
import { useRecoilState } from 'recoil'
|
import { useRecoilState } from 'recoil'
|
||||||
import { fontSizeState, canvasSizeState } from '@/store/canvasAtom'
|
import { fontSizeState, canvasSizeState } from '@/store/canvasAtom'
|
||||||
|
|
||||||
export default function Roof2() {
|
export default function Roof2() {
|
||||||
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots } =
|
const {
|
||||||
useCanvas('canvas')
|
canvas,
|
||||||
|
handleRedo,
|
||||||
|
handleUndo,
|
||||||
|
setCanvasBackgroundWithDots,
|
||||||
|
saveImage,
|
||||||
|
} = useCanvas('canvas')
|
||||||
|
|
||||||
//canvas 기본 사이즈
|
//canvas 기본 사이즈
|
||||||
const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
|
const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState)
|
||||||
@ -86,6 +92,9 @@ export default function Roof2() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
canvas?.add(polygon)
|
canvas?.add(polygon)
|
||||||
|
console.log(polygon)
|
||||||
|
|
||||||
|
// polygon.fillCell({ width: 50, height: 30, padding: 10 })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +121,70 @@ export default function Roof2() {
|
|||||||
canvasSizeMode()
|
canvasSizeMode()
|
||||||
}, [verticalSize, horizontalSize])
|
}, [verticalSize, horizontalSize])
|
||||||
|
|
||||||
|
const addPolygonType1 = () => {
|
||||||
|
if (canvas) {
|
||||||
|
const polygon = new QPolygon(
|
||||||
|
[
|
||||||
|
{ x: 100, y: 100 },
|
||||||
|
{ x: 800, y: 100 },
|
||||||
|
{ x: 800, y: 800 },
|
||||||
|
{ x: 500, y: 800 },
|
||||||
|
{ x: 500, y: 400 },
|
||||||
|
{ x: 100, y: 400 },
|
||||||
|
],
|
||||||
|
{
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
selectable: true,
|
||||||
|
fontSize: fontSize,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
canvas?.add(polygon)
|
||||||
|
|
||||||
|
polygon.fillCell({ width: 20, height: 20, padding: 10 })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotate = () => {
|
||||||
|
const rect = canvas?.getObjects().find((obj) => obj.type === 'QRect')
|
||||||
|
if (!rect) {
|
||||||
|
alert('사각형을 먼저 만들어주세요.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const angle = prompt('각도를 입력해주세요.', '0')
|
||||||
|
if (rect) {
|
||||||
|
rect.angle = parseInt(angle)
|
||||||
|
canvas?.renderAll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const makeQPolygon2 = () => {
|
||||||
|
if (canvas) {
|
||||||
|
const polygon2 = new QPolygon2(
|
||||||
|
[
|
||||||
|
{ x: 100, y: 100 },
|
||||||
|
{ x: 800, y: 100 },
|
||||||
|
{ x: 800, y: 800 },
|
||||||
|
{ x: 500, y: 800 },
|
||||||
|
{ x: 500, y: 400 },
|
||||||
|
{ x: 100, y: 400 },
|
||||||
|
],
|
||||||
|
{
|
||||||
|
fill: 'transparent',
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 2,
|
||||||
|
selectable: true,
|
||||||
|
fontSize: fontSize,
|
||||||
|
},
|
||||||
|
canvas,
|
||||||
|
)
|
||||||
|
|
||||||
|
canvas?.add(polygon2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{canvas && (
|
{canvas && (
|
||||||
@ -230,6 +303,34 @@ export default function Roof2() {
|
|||||||
>
|
>
|
||||||
점선 추가
|
점선 추가
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-30 mx-2 p-2 rounded bg-gray-500 text-white"
|
||||||
|
onClick={() => {
|
||||||
|
addPolygonType1()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
폴리곤 type 1
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-30 mx-2 p-2 rounded bg-gray-500 text-white"
|
||||||
|
onClick={() => {
|
||||||
|
saveImage()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
저장
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-30 mx-2 p-2 rounded bg-gray-500 text-white"
|
||||||
|
onClick={rotate}
|
||||||
|
>
|
||||||
|
회전
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="w-30 mx-2 p-2 rounded bg-gray-500 text-white"
|
||||||
|
onClick={makeQPolygon2}
|
||||||
|
>
|
||||||
|
QPolygon2
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-center flex-col items-center">
|
<div className="flex justify-center flex-col items-center">
|
||||||
<div className="m-2 p-2 w-80">
|
<div className="m-2 p-2 w-80">
|
||||||
|
|||||||
@ -40,6 +40,7 @@ export default class QPolygon extends fabric.Polygon {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.on('modified', (e) => {
|
this.on('modified', (e) => {
|
||||||
|
console.log(this)
|
||||||
this.#addLengthText()
|
this.#addLengthText()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -61,7 +62,6 @@ export default class QPolygon extends fabric.Polygon {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#addLengthText() {
|
#addLengthText() {
|
||||||
return false
|
|
||||||
if (this.#text.length > 0) {
|
if (this.#text.length > 0) {
|
||||||
this.#text.forEach((text) => {
|
this.#text.forEach((text) => {
|
||||||
this.canvas.remove(text)
|
this.canvas.remove(text)
|
||||||
@ -75,13 +75,13 @@ export default class QPolygon extends fabric.Polygon {
|
|||||||
const scaleX = this.scaleX
|
const scaleX = this.scaleX
|
||||||
const scaleY = this.scaleY
|
const scaleY = this.scaleY
|
||||||
|
|
||||||
const points = this.points
|
const points = this.getCurrentPoints()
|
||||||
|
|
||||||
for (let i = 0; i < points.length; i++) {
|
for (let i = 0; i < points.length; i++) {
|
||||||
const start = points[i]
|
const start = points[i]
|
||||||
const end = points[(i + 1) % points.length]
|
const end = points[(i + 1) % points.length]
|
||||||
const dx = end.x - start.x
|
const dx = (end.x - start.x) * scaleX
|
||||||
const dy = end.y - start.y
|
const dy = (end.y - start.y) * scaleY
|
||||||
const length = Math.sqrt(dx * dx + dy * dy)
|
const length = Math.sqrt(dx * dx + dy * dy)
|
||||||
|
|
||||||
const midPoint = new fabric.Point(
|
const midPoint = new fabric.Point(
|
||||||
@ -236,8 +236,4 @@ export default class QPolygon extends fabric.Polygon {
|
|||||||
|
|
||||||
return intersects % 2 === 1
|
return intersects % 2 === 1
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentOptions = () => {
|
|
||||||
return this.options
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
79
src/components/fabric/QPolygon2.js
Normal file
79
src/components/fabric/QPolygon2.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { fabric } from 'fabric'
|
||||||
|
|
||||||
|
export default class QPolygon2 extends fabric.Group {
|
||||||
|
type = 'QPolygon2'
|
||||||
|
polygon
|
||||||
|
points
|
||||||
|
texts = []
|
||||||
|
canvas
|
||||||
|
constructor(points, options, canvas) {
|
||||||
|
const polygon = new fabric.Polygon(points, options)
|
||||||
|
super([polygon], {})
|
||||||
|
this.points = points
|
||||||
|
this.polygon = polygon
|
||||||
|
this.canvas = canvas
|
||||||
|
|
||||||
|
this.#init()
|
||||||
|
this.#addEvent()
|
||||||
|
}
|
||||||
|
|
||||||
|
#init() {
|
||||||
|
this.#addLengthText()
|
||||||
|
}
|
||||||
|
|
||||||
|
#addEvent() {
|
||||||
|
this.on('modified', () => {
|
||||||
|
// this.#addLengthText()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#addLengthText() {
|
||||||
|
const points = this.getCurrentPoints()
|
||||||
|
|
||||||
|
points.forEach((start, i) => {
|
||||||
|
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 midPoint = new fabric.Point(
|
||||||
|
(start.x + end.x) / 2,
|
||||||
|
(start.y + end.y) / 2,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (this.texts[i]) {
|
||||||
|
// Update existing text
|
||||||
|
this.texts[i].set({
|
||||||
|
text: length.toFixed(0),
|
||||||
|
left: midPoint.x,
|
||||||
|
top: midPoint.y,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
// Create new text object if it doesn't exist
|
||||||
|
const text = new fabric.Text(length.toFixed(0), {
|
||||||
|
left: midPoint.x,
|
||||||
|
top: midPoint.y,
|
||||||
|
fontSize: 16,
|
||||||
|
selectable: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
this.texts.push(text)
|
||||||
|
this.addWithUpdate(text)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.canvas.renderAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
getCurrentPoints() {
|
||||||
|
const scaleX = this.scaleX
|
||||||
|
const scaleY = this.scaleY
|
||||||
|
|
||||||
|
return this.points.map((point) => {
|
||||||
|
return {
|
||||||
|
x: point.x * scaleX,
|
||||||
|
y: point.y * scaleY,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user