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