added dots background
This commit is contained in:
+132
-30
@@ -1,9 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import React, { useState, useRef, useCallback } from 'react'
|
import React, { useState, useRef, useCallback, useEffect } from 'react'
|
||||||
import { useDrop } from 'react-dnd'
|
import { useDrop } from 'react-dnd'
|
||||||
import { DraggableItem } from './DraggableItem'
|
import { DraggableItem } from './DraggableItem';
|
||||||
import { useElements } from '../context/ElementsContext'
|
import { useElements } from '../context/ElementsContext';
|
||||||
|
|
||||||
interface Item {
|
interface Item {
|
||||||
id: string
|
id: string
|
||||||
@@ -34,11 +34,110 @@ const mergeElements = async (type1: string, type2: string) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DropArea: React.FC = () => {
|
const DropArea = () => {
|
||||||
const [items, setItems] = useState<Item[]>([])
|
const [items, setItems] = useState<Item[]>([])
|
||||||
const [maxZIndex, setMaxZIndex] = useState(0)
|
const [maxZIndex, setMaxZIndex] = useState(0)
|
||||||
const dropAreaRef = useRef<HTMLDivElement>(null)
|
const dropAreaRef = useRef<HTMLDivElement>(null)
|
||||||
const { addElement } = useElements()
|
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||||||
|
|
||||||
|
// Canvas animation logic
|
||||||
|
useEffect(() => {
|
||||||
|
const canvas = canvasRef.current
|
||||||
|
if (!canvas) return
|
||||||
|
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
if (!ctx) return
|
||||||
|
|
||||||
|
let animationFrameId: number
|
||||||
|
let width: number
|
||||||
|
let height: number
|
||||||
|
|
||||||
|
const dots: any[] = []
|
||||||
|
const numDots = 150
|
||||||
|
const dotSizeRange = { min: 1, max: 3 }
|
||||||
|
const moveSpeed = 0.15
|
||||||
|
|
||||||
|
class Dot {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
size: number
|
||||||
|
vx: number
|
||||||
|
vy: number
|
||||||
|
opacity: number
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.x = Math.random() * width
|
||||||
|
this.y = Math.random() * height
|
||||||
|
this.size = Math.random() * (dotSizeRange.max - dotSizeRange.min) + dotSizeRange.min
|
||||||
|
this.vx = (Math.random() - 0.5) * moveSpeed
|
||||||
|
this.vy = (Math.random() - 0.5) * moveSpeed
|
||||||
|
this.opacity = Math.random() * 0.5 + 0.1
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
this.x += this.vx
|
||||||
|
this.y += this.vy
|
||||||
|
|
||||||
|
if (this.x < 0 || this.x > width) this.vx *= -1
|
||||||
|
if (this.y < 0 || this.y > height) this.vy *= -1
|
||||||
|
}
|
||||||
|
|
||||||
|
draw() {
|
||||||
|
if (!ctx) return
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2)
|
||||||
|
ctx.fillStyle = `rgba(200, 200, 200, ${this.opacity})`
|
||||||
|
ctx.fill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function initDots() {
|
||||||
|
const gridSize = Math.sqrt(numDots)
|
||||||
|
const cellWidth = width / gridSize
|
||||||
|
const cellHeight = height / gridSize
|
||||||
|
|
||||||
|
for (let i = 0; i < numDots; i++) {
|
||||||
|
const dot = new Dot()
|
||||||
|
const gridX = i % gridSize
|
||||||
|
const gridY = Math.floor(i / gridSize)
|
||||||
|
|
||||||
|
dot.x = (gridX + Math.random()) * cellWidth
|
||||||
|
dot.y = (gridY + Math.random()) * cellHeight
|
||||||
|
|
||||||
|
dots.push(dot)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeCanvas() {
|
||||||
|
width = window.innerWidth
|
||||||
|
height = window.innerHeight
|
||||||
|
canvas.width = width
|
||||||
|
canvas.height = height
|
||||||
|
dots.length = 0
|
||||||
|
initDots()
|
||||||
|
}
|
||||||
|
|
||||||
|
function animate() {
|
||||||
|
ctx.clearRect(0, 0, width, height)
|
||||||
|
|
||||||
|
dots.forEach(dot => {
|
||||||
|
dot.update()
|
||||||
|
dot.draw()
|
||||||
|
})
|
||||||
|
|
||||||
|
animationFrameId = requestAnimationFrame(animate)
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeCanvas()
|
||||||
|
animate()
|
||||||
|
|
||||||
|
window.addEventListener('resize', resizeCanvas)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', resizeCanvas)
|
||||||
|
cancelAnimationFrame(animationFrameId)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
const moveItem = useCallback((id: string, left: number, top: number) => {
|
const moveItem = useCallback((id: string, left: number, top: number) => {
|
||||||
setItems((prevItems) => {
|
setItems((prevItems) => {
|
||||||
@@ -53,15 +152,13 @@ const DropArea: React.FC = () => {
|
|||||||
const mergeItems = useCallback(async (item1: Item, item2: Item) => {
|
const mergeItems = useCallback(async (item1: Item, item2: Item) => {
|
||||||
const result = await mergeElements(item1.type, item2.type)
|
const result = await mergeElements(item1.type, item2.type)
|
||||||
if (result) {
|
if (result) {
|
||||||
// Add the new element type to the sidebar
|
|
||||||
addElement(result.type, result.emoji)
|
|
||||||
return {
|
return {
|
||||||
...item1,
|
...item1,
|
||||||
type: result.type
|
type: result.type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return item1
|
return item1
|
||||||
}, [addElement])
|
}, [])
|
||||||
|
|
||||||
const [, drop] = useDrop(() => ({
|
const [, drop] = useDrop(() => ({
|
||||||
accept: ['item', 'new-item'],
|
accept: ['item', 'new-item'],
|
||||||
@@ -85,7 +182,6 @@ const DropArea: React.FC = () => {
|
|||||||
if (targetItem) {
|
if (targetItem) {
|
||||||
const mergedItem = await mergeItems(item, targetItem)
|
const mergedItem = await mergeItems(item, targetItem)
|
||||||
setItems(prevItems => {
|
setItems(prevItems => {
|
||||||
// Remove both original items and add the merged item
|
|
||||||
const filteredItems = prevItems.filter(i => i.id !== item.id && i.id !== targetItem.id)
|
const filteredItems = prevItems.filter(i => i.id !== item.id && i.id !== targetItem.id)
|
||||||
return [...filteredItems, {
|
return [...filteredItems, {
|
||||||
...mergedItem,
|
...mergedItem,
|
||||||
@@ -118,7 +214,6 @@ const DropArea: React.FC = () => {
|
|||||||
if (targetItem) {
|
if (targetItem) {
|
||||||
const mergedItem = await mergeItems(newItem, targetItem)
|
const mergedItem = await mergeItems(newItem, targetItem)
|
||||||
setItems(prevItems => {
|
setItems(prevItems => {
|
||||||
// Remove the original item and add the merged item
|
|
||||||
const filteredItems = prevItems.filter(i => i.id !== targetItem.id)
|
const filteredItems = prevItems.filter(i => i.id !== targetItem.id)
|
||||||
return [...filteredItems, {
|
return [...filteredItems, {
|
||||||
...mergedItem,
|
...mergedItem,
|
||||||
@@ -137,27 +232,34 @@ const DropArea: React.FC = () => {
|
|||||||
}), [moveItem, maxZIndex, items, mergeItems])
|
}), [moveItem, maxZIndex, items, mergeItems])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="relative w-full h-full">
|
||||||
ref={(node) => {
|
<time dateTime="2016-10-25" suppressHydrationWarning />
|
||||||
drop(node)
|
<canvas
|
||||||
dropAreaRef.current = node
|
ref={canvasRef}
|
||||||
}}
|
className="fixed inset-0 w-full h-full bg-white"
|
||||||
className="w-full h-full relative bg-white"
|
style={{ zIndex: -1 }}
|
||||||
>
|
/>
|
||||||
{items.map((item) => (
|
<div
|
||||||
<DraggableItem
|
ref={(node) => {
|
||||||
key={item.id}
|
drop(node)
|
||||||
id={item.id}
|
dropAreaRef.current = node
|
||||||
type={item.type}
|
}}
|
||||||
left={item.left}
|
className="w-full h-full relative bg-transparent"
|
||||||
top={item.top}
|
>
|
||||||
zIndex={item.zIndex}
|
{items.map((item) => (
|
||||||
moveItem={moveItem}
|
<DraggableItem
|
||||||
/>
|
key={item.id}
|
||||||
))}
|
id={item.id}
|
||||||
|
type={item.type}
|
||||||
|
left={item.left}
|
||||||
|
top={item.top}
|
||||||
|
zIndex={item.zIndex}
|
||||||
|
moveItem={moveItem}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default DropArea
|
export default DropArea
|
||||||
|
|
||||||
Reference in New Issue
Block a user