Add fog of war example (#4025)
This PR adds a cute fog of war example. ![Kapture 2024-06-26 at 20 47 37](https://github.com/tldraw/tldraw/assets/23072548/b426776f-b027-419e-9770-29f5c7ab2563) ### Change Type - [x] `docs` - [x] `improvement` ### Release Notes - Adds fog of war example.
This commit is contained in:
parent
d686b1f0c5
commit
3d07262e20
2 changed files with 116 additions and 0 deletions
106
apps/examples/src/examples/fog-of-war/FogOfWarExample.tsx
Normal file
106
apps/examples/src/examples/fog-of-war/FogOfWarExample.tsx
Normal file
|
@ -0,0 +1,106 @@
|
|||
import { useEffect, useRef } from 'react'
|
||||
import { Box, TLComponents, Tldraw, Vec, useEditor, useReactor } from 'tldraw'
|
||||
import 'tldraw/tldraw.css'
|
||||
|
||||
const CELL_SIZE = 32
|
||||
const COUNT = 100
|
||||
|
||||
const boxes: Box[][] = []
|
||||
const cells: boolean[][] = []
|
||||
for (let i = 0; i < COUNT; i++) {
|
||||
cells[i] = []
|
||||
boxes[i] = []
|
||||
for (let j = 0; j < COUNT; j++) {
|
||||
cells[i].push(false)
|
||||
boxes[i].push(
|
||||
new Box((i - COUNT / 2) * CELL_SIZE, (j - COUNT / 2) * CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export function Fog() {
|
||||
const rCanvas = useRef<HTMLCanvasElement>(null)
|
||||
const rVisibility = useRef<boolean[][]>(cells)
|
||||
const editor = useEditor()
|
||||
|
||||
useEffect(() => {
|
||||
const cvs = rCanvas.current!
|
||||
const rect = cvs.getBoundingClientRect()
|
||||
cvs.width = rect.width
|
||||
cvs.height = rect.height
|
||||
}, [editor])
|
||||
|
||||
useReactor(
|
||||
'update fog',
|
||||
() => {
|
||||
const cells = rVisibility.current
|
||||
const shapes = editor.getCurrentPageShapes()
|
||||
for (const shape of shapes) {
|
||||
const point = editor.getShapePageBounds(shape)!.point
|
||||
const geometry = editor.getShapeGeometry(shape)
|
||||
for (let i = 0; i < boxes.length; i++) {
|
||||
for (let j = 0; j < boxes[i].length; j++) {
|
||||
const box = boxes[i][j]
|
||||
box.translate(Vec.Neg(point))
|
||||
if (geometry.bounds.collides(box)) {
|
||||
cells[i][j] = true
|
||||
}
|
||||
box.translate(point)
|
||||
}
|
||||
}
|
||||
}
|
||||
const cvs = rCanvas.current!
|
||||
const ctx = cvs.getContext('2d')!
|
||||
|
||||
ctx.resetTransform()
|
||||
const camera = editor.getCamera()
|
||||
|
||||
ctx.clearRect(0, 0, cvs.width, cvs.height)
|
||||
ctx.fillStyle = 'rgba(0,0,0,0.9)'
|
||||
ctx.fillRect(0, 0, cvs.width, cvs.height)
|
||||
|
||||
ctx.translate(100, 100)
|
||||
ctx.scale(camera.z, camera.z)
|
||||
ctx.translate(camera.x, camera.y)
|
||||
|
||||
for (let i = 0; i < boxes.length; i++) {
|
||||
for (let j = 0; j < boxes[i].length; j++) {
|
||||
if (!cells[i][j]) continue
|
||||
const box = boxes[i][j]
|
||||
ctx.filter = 'drop-shadow(100px)'
|
||||
ctx.clearRect(box.x, box.y, box.width, box.height)
|
||||
}
|
||||
}
|
||||
},
|
||||
[editor]
|
||||
)
|
||||
|
||||
return (
|
||||
<canvas
|
||||
ref={rCanvas}
|
||||
style={{
|
||||
zIndex: 999999,
|
||||
position: 'absolute',
|
||||
top: -100,
|
||||
left: -100,
|
||||
width: 'calc(100% + 200px)',
|
||||
height: 'calc(100% + 200px)',
|
||||
WebkitFilter: 'blur(15px)',
|
||||
filter: 'blur(15px)',
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const components: TLComponents = {
|
||||
InFrontOfTheCanvas: Fog,
|
||||
}
|
||||
|
||||
export default function BasicExample() {
|
||||
return (
|
||||
<div className="tldraw__editor">
|
||||
<Tldraw persistenceKey="example" components={components} />
|
||||
</div>
|
||||
)
|
||||
}
|
10
apps/examples/src/examples/fog-of-war/README.md
Normal file
10
apps/examples/src/examples/fog-of-war/README.md
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
title: Fog of war
|
||||
component: ./FogOfWarExample.tsx
|
||||
category: basic
|
||||
keywords: [ui, fog, overlay]
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
This example shows how you might keep an HTML canvas in sync with canvas content. It implements a simple "fog of war" effect, where the canvas is covered by a black overlay that can be cleared by drawing shapes on the canvas.
|
Loading…
Reference in a new issue