Skip to content

Instantly share code, notes, and snippets.

@drecali
Created December 30, 2021 12:17
Show Gist options
  • Save drecali/cc5e7289381f259477788eb9e53b5dba to your computer and use it in GitHub Desktop.
Save drecali/cc5e7289381f259477788eb9e53b5dba to your computer and use it in GitHub Desktop.
Controlled circular brush cursor

Custom circle cursor like Photoshop

For an HTML canvas app, I made a circular cursor just like in Photoshop. Its size changes dynamically while keeping the same stroke width.

I wanted to implement this as a custom cursor because the max size was 100px (under the 128px limit imposed by browsers) and it was more elegant because the browser internally figures out the position of the cursor, so it simplifies the code. It worked beautifully! Except...

Unfortunately, scammers ruined it for us 🤬. Browsers will not render any custom cursor >32px if it overlaps any of the browser UI. So if any part of the cursor exceeds the nomral webpage area, the entire cursor won't be rendered.

I wanted to save this code because I like my solution. Until about 2018, it would have worked! The only issue is the cursor would have overlapped other elements of the app's UI, so a normal SVG implementation is probably best.

I made a demo illustrating this on CodePen. I also included the rabbithole that resulted from figuring this out.

Here's a video of the way scammers ruined this: https://user-images.githubusercontent.com/24983797/147750645-3e808a3c-b874-4f63-b51d-a0fcd49a24e7.mov

import React, { useState } from "react"';
import { useSelector } from "react-redux";
import { getBrushSizeSelector } from "dux/brush/selectors";
const CanvasWithCustomCircleCursor = () => {
const diameter = useSelector(getBrushSizeSelector);
const radius = diameter / 2;
const circleBorder = 3;
return (
<canvas style={{ cursor: `url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='${diameter}' height='${diameter}' viewBox='${-circleBorder} ${-circleBorder} ${
diameter + circleBorder * 2
} ${
diameter + circleBorder * 2
}' > <circle id='r' cx='${radius}' cy='${radius}' r='${radius}' stroke='white' stroke-width='${
circleBorder * 2
}' fill='none'/> <circle id='r' cx='${radius}' cy='${radius}' r='${radius}' stroke='black' stroke-width='${circleBorder}' fill='none'/> </svg>") ${radius} ${radius}, not-allowed`
}}>
)
}
export default CanvasWithCustomCircleCursor;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment