Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions components/board/board-elements/eraser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import getStroke from "perfect-freehand"

import { getSvgPathFromStroke } from "@/lib/utils"

interface PathProps {
x: number
y: number
points: number[][]
fill?: string
onPointerDown?: (e: React.PointerEvent) => void
stroke?: string
}

export const Eraser = ({
x,
y,
points,
fill,
onPointerDown,
stroke,
}: PathProps) => {
return (
<path
className="drop-shadow-md"
onPointerDown={onPointerDown}
d={getSvgPathFromStroke(
getStroke(points, {
size: 10,
thinning: 0.5,
smoothing: 0.5,
streamline: 0.5,
}),
)}
style={{
transform: `translate(${x}px, ${y}px)`,
}}
x={0}
y={0}
fill="none"
stroke="#fff"
strokeWidth={5}
/>
)
}
4 changes: 2 additions & 2 deletions components/board/broadcast/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const Broadcast = () => {

useEffect(() => {
function onKeyUp(e: KeyboardEvent) {
if (e.key === "7") {
if (e.key === "8") {
setState({
mode: CursorMode.Chat,
previousMessage: null,
Expand All @@ -29,7 +29,7 @@ export const Broadcast = () => {
window.addEventListener("keyup", onKeyUp)

function onKeyDown(e: KeyboardEvent) {
if (e.key === "7") {
if (e.key === "8") {
e.preventDefault()
}
}
Expand Down
12 changes: 12 additions & 0 deletions components/board/canvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,11 @@ export const Canvas = ({ workspaceId }: ICanvasProps) => {
}

const id = nanoid()
const newLayer = penPointsToPathLayer(pencilDraft, lastUsedColor)
// If the current mode is Eraser, set the fill color to white (or your canvas background color)
if (canvasState.mode === CanvasMode.Erasing) {
newLayer.fill = "#fff" // white color for erasing
}
liveLayers.set(
id,
new LiveObject(penPointsToPathLayer(pencilDraft, lastUsedColor)),
Expand Down Expand Up @@ -439,6 +444,13 @@ export const Canvas = ({ workspaceId }: ICanvasProps) => {
setCanvasState({ mode: CanvasMode.Pencil })
break
}
case "7": {
setCanvasState({
mode: CanvasMode.Erasing,
layerType: LayerType.Eraser,
})
break
}
case "z": {
if (e.ctrlKey || e.metaKey) {
if (e.shiftKey) {
Expand Down
10 changes: 10 additions & 0 deletions components/board/layer-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { colorToCss } from "@/lib/utils"
import { useStorage } from "@/liveblocks.config"
import { LayerType } from "@/types/canvas"
import { Ellipse, Note, Path, Rectangle, Text } from "./board-elements"
import { Eraser } from "./board-elements/eraser"

interface ILayerPreviewProps {
id: string
Expand Down Expand Up @@ -67,6 +68,15 @@ export const LayerPreview = memo(
selectionColor={selectionColor}
/>
)
case LayerType.Eraser:
return (
<Eraser
x={layer.x}
y={layer.y}
points={layer.points}
onPointerDown={(e) => onLayerPointerDown(e, id)}
/>
)
default:
return null
}
Expand Down
18 changes: 17 additions & 1 deletion components/board/toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Circle,
Eraser,
MessageSquareText,
MousePointer2,
Pencil,
Expand Down Expand Up @@ -117,7 +118,22 @@ export const Toolbar = ({
}
isActive={canvasState.mode === CanvasMode.Pencil}
/>
<ToolButton label="Chat" icon={MessageSquareText} shortcut={7} />
<ToolButton
label="Eraser"
icon={Eraser}
shortcut={7}
onClick={() =>
setCanvasState({
mode: CanvasMode.Erasing,
layerType: LayerType.Eraser,
})
}
isActive={
canvasState.mode === CanvasMode.Erasing &&
canvasState.layerType === LayerType.Eraser
}
/>
<ToolButton label="Chat" icon={MessageSquareText} shortcut={8} />
<ToolButton
label="Undo"
icon={Undo2}
Expand Down
10 changes: 5 additions & 5 deletions lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { type ClassValue, clsx } from "clsx"
import { clsx, type ClassValue } from "clsx"
import React from "react"
import { twMerge } from "tailwind-merge"

Expand Down Expand Up @@ -36,7 +36,7 @@ export function connectionIdToColor(connectionId: number): string {

export function pointerEventToCanvasPoint(
e: React.PointerEvent,
camera: Camera
camera: Camera,
) {
return {
x: Math.round(e.clientX) - camera.x,
Expand Down Expand Up @@ -85,7 +85,7 @@ export function findIntersectingLayersWithRectangle(
layerIds: readonly string[],
layers: ReadonlyMap<string, Layer>,
a: Point,
b: Point
b: Point,
) {
const rect = {
x: Math.min(a.x, b.x),
Expand Down Expand Up @@ -126,7 +126,7 @@ export function getContrastingTextColor(color: Color) {

export function penPointsToPathLayer(
points: number[][],
color: Color
color: Color,
): PathLayer {
if (points.length < 2) {
throw new Error("Cannot transform points with less than 2 points")
Expand Down Expand Up @@ -177,7 +177,7 @@ export function getSvgPathFromStroke(stroke: number[][]) {
acc.push(x0, y0, (x0 + x1) / 2, (y0 + y1) / 2)
return acc
},
["M", ...stroke[0], "Q"]
["M", ...stroke[0], "Q"],
)

d.push("Z")
Expand Down
18 changes: 18 additions & 0 deletions types/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export enum LayerType {
Path,
Text,
Note,
Eraser,
}

export type RectangleLayer = {
Expand Down Expand Up @@ -48,6 +49,17 @@ export type PathLayer = {
value?: string
}

export type EraserLayer = {
type: LayerType.Eraser
x: number
y: number
height: number
width: number
fill: string
points: number[][]
value?: string
}

export type TextLayer = {
type: LayerType.Text
x: number
Expand Down Expand Up @@ -123,6 +135,10 @@ export type CanvasState =
| {
mode: CanvasMode.Pencil
}
| {
mode: CanvasMode.Erasing
layerType: LayerType.Eraser
}
| {
mode: CanvasMode.Pressing
origin: Point
Expand Down Expand Up @@ -159,6 +175,7 @@ export enum CanvasMode {
Inserting,
Resizing,
Pencil,
Erasing,
}

export enum CursorMode {
Expand All @@ -172,5 +189,6 @@ export type Layer =
| RectangleLayer
| EllipseLayer
| PathLayer
| EraserLayer
| TextLayer
| NoteLayer