add pixel picker (fixes #55)
right click & middle click now get triggered by keybinds (uses auxclick event)
This commit is contained in:
parent
7964954a0d
commit
0e97316096
|
@ -33,10 +33,6 @@ const Cursor = () => {
|
|||
const { cursor } = useAppContext();
|
||||
const [color, setColor] = useState<string>();
|
||||
|
||||
useEffect(() => {
|
||||
console.log("color", color);
|
||||
}, [color]);
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof cursor.color === "number") {
|
||||
const color = Canvas.instance?.Pallete.getColor(cursor.color);
|
||||
|
@ -71,17 +67,19 @@ const CanvasInner = () => {
|
|||
useAppContext();
|
||||
const PanZoom = useContext(RendererContext);
|
||||
|
||||
const handlePixelWhois = useCallback(
|
||||
({ clientX, clientY }: { clientX: number; clientY: number }) => {
|
||||
/**
|
||||
* Is the canvas coordinate within the bounds of the canvas?
|
||||
*/
|
||||
const isCoordInCanvas = useCallback(
|
||||
(x: number, y: number): boolean => {
|
||||
if (!canvas.current) {
|
||||
console.warn(
|
||||
"[CanvasWrapper#handlePixelWhois] canvas instance does not exist"
|
||||
"[CanvasWrapper#isCoordInCanvas] canvas instance does not exist"
|
||||
);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
const [x, y] = canvas.current.screenToPos(clientX, clientY);
|
||||
if (x < 0 || y < 0) return; // discard if out of bounds
|
||||
if (x < 0 || y < 0) return false; // not positive, impossible to be on canvas
|
||||
|
||||
// canvas size can dynamically change, so we need to check the current config
|
||||
// we're depending on canvas.instance's config so we don't have to use a react dependency
|
||||
|
@ -92,14 +90,31 @@ const CanvasInner = () => {
|
|||
},
|
||||
} = canvas.current.getConfig();
|
||||
|
||||
if (x >= width || y >= height) return; // out of bounds
|
||||
if (x >= width || y >= height) return false; // out of bounds
|
||||
} else {
|
||||
// although this should never happen, log it
|
||||
console.warn(
|
||||
"[CanvasWrapper#handlePixelWhois] canvas config is not available yet"
|
||||
"[CanvasWrapper#isCoordInCanvas] canvas config is not available yet"
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[canvas.current]
|
||||
);
|
||||
|
||||
const handlePixelWhois = useCallback(
|
||||
({ clientX, clientY }: { clientX: number; clientY: number }) => {
|
||||
if (!canvas.current) {
|
||||
console.warn(
|
||||
"[CanvasWrapper#handlePixelWhois] canvas instance does not exist"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const [x, y] = canvas.current.screenToPos(clientX, clientY);
|
||||
if (!isCoordInCanvas(x, y)) return; // out of bounds
|
||||
|
||||
// .......
|
||||
// .......
|
||||
// .......
|
||||
|
@ -114,6 +129,30 @@ const CanvasInner = () => {
|
|||
[canvas.current]
|
||||
);
|
||||
|
||||
const handlePickPixel = useCallback(
|
||||
({ clientX, clientY }: { clientX: number; clientY: number }) => {
|
||||
if (!canvas.current) {
|
||||
console.warn(
|
||||
"[CanvasWrapper#handlePickPixel] canvas instance does not exist"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const [x, y] = canvas.current.screenToPos(clientX, clientY);
|
||||
if (!isCoordInCanvas(x, y)) return; // out of bounds
|
||||
|
||||
const pixel = canvas.current.getPixel(x, y);
|
||||
if (!pixel) return;
|
||||
|
||||
// no need to use canvas#setCursor as Palette.tsx already does that
|
||||
setCursor((v) => ({
|
||||
...v,
|
||||
color: pixel.color,
|
||||
}));
|
||||
},
|
||||
[canvas.current]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvasRef.current) return;
|
||||
canvas.current = new Canvas(canvasRef.current!, PanZoom);
|
||||
|
@ -126,9 +165,11 @@ const CanvasInner = () => {
|
|||
});
|
||||
|
||||
KeybindManager.on("PIXEL_WHOIS", handlePixelWhois);
|
||||
KeybindManager.on("PICK_COLOR", handlePickPixel);
|
||||
|
||||
return () => {
|
||||
KeybindManager.off("PIXEL_WHOIS", handlePixelWhois);
|
||||
KeybindManager.off("PICK_COLOR", handlePickPixel);
|
||||
canvas.current!.destroy();
|
||||
};
|
||||
}, [PanZoom]);
|
||||
|
|
|
@ -3,21 +3,14 @@ import { useAppContext } from "../../contexts/AppContext";
|
|||
import { Canvas } from "../../lib/canvas";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faXmark } from "@fortawesome/free-solid-svg-icons";
|
||||
import { IPaletteContext } from "@sc07-canvas/lib/src/net";
|
||||
import { KeybindManager } from "../../lib/keybinds";
|
||||
|
||||
export const Palette = () => {
|
||||
const { config, user, setCursor } = useAppContext<true>();
|
||||
const [pallete, setPallete] = useState<IPaletteContext>({});
|
||||
const { config, user, cursor, setCursor } = useAppContext<true>();
|
||||
|
||||
useEffect(() => {
|
||||
Canvas.instance?.updatePallete(pallete);
|
||||
|
||||
setCursor((v) => ({
|
||||
...v,
|
||||
color: pallete.color,
|
||||
}));
|
||||
}, [pallete]);
|
||||
Canvas.instance?.updateCursor(cursor.color);
|
||||
}, [cursor]);
|
||||
|
||||
useEffect(() => {
|
||||
const handleDeselect = () => {
|
||||
|
@ -42,8 +35,8 @@ export const Palette = () => {
|
|||
className="pallete-color--deselect"
|
||||
title="Deselect Color"
|
||||
onClick={() => {
|
||||
setPallete(({ color, ...pallete }) => {
|
||||
return pallete;
|
||||
setCursor(({ color, ...cursor }) => {
|
||||
return cursor;
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
@ -53,7 +46,7 @@ export const Palette = () => {
|
|||
<button
|
||||
key={color.id}
|
||||
aria-label={color.name}
|
||||
className={["pallete-color", color.id === pallete.color && "active"]
|
||||
className={["pallete-color", color.id === cursor.color && "active"]
|
||||
.filter((a) => a)
|
||||
.join(" ")}
|
||||
style={{
|
||||
|
@ -61,9 +54,9 @@ export const Palette = () => {
|
|||
}}
|
||||
title={color.name}
|
||||
onClick={() => {
|
||||
setPallete((pallete) => {
|
||||
setCursor((cursor) => {
|
||||
return {
|
||||
...pallete,
|
||||
...cursor,
|
||||
color: color.id,
|
||||
};
|
||||
});
|
||||
|
|
|
@ -1,10 +1,5 @@
|
|||
import EventEmitter from "eventemitter3";
|
||||
import {
|
||||
ClientConfig,
|
||||
IPaletteContext,
|
||||
IPosition,
|
||||
Pixel,
|
||||
} from "@sc07-canvas/lib/src/net";
|
||||
import { ClientConfig, IPosition, Pixel } from "@sc07-canvas/lib/src/net";
|
||||
import Network from "./network";
|
||||
import {
|
||||
ClickEvent,
|
||||
|
@ -34,7 +29,7 @@ export class Canvas extends EventEmitter<CanvasEvents> {
|
|||
private canvas: HTMLCanvasElement;
|
||||
private PanZoom: PanZoom;
|
||||
|
||||
private cursor = { x: -1, y: -1 };
|
||||
private cursor: { x: number; y: number; color?: number } = { x: -1, y: -1 };
|
||||
private pixels: {
|
||||
[x_y: string]: { color: number; type: "full" | "pending" };
|
||||
} = {};
|
||||
|
@ -174,6 +169,10 @@ export class Canvas extends EventEmitter<CanvasEvents> {
|
|||
return pixels;
|
||||
}
|
||||
|
||||
getPixel(x: number, y: number): { color: number } | undefined {
|
||||
return this.pixels[x + "_" + y];
|
||||
}
|
||||
|
||||
handleLongPress = (clientX: number, clientY: number) => {
|
||||
KeybindManager.handleInteraction(
|
||||
{
|
||||
|
@ -289,16 +288,15 @@ export class Canvas extends EventEmitter<CanvasEvents> {
|
|||
getRenderer().usePixel({ x, y, hex: palette?.hex || "null" });
|
||||
};
|
||||
|
||||
palleteCtx: IPaletteContext = {};
|
||||
Pallete = {
|
||||
getColor: (colorId: number) => {
|
||||
return this.config.pallete.colors.find((c) => c.id === colorId);
|
||||
},
|
||||
|
||||
getSelectedColor: () => {
|
||||
if (!this.palleteCtx.color) return undefined;
|
||||
if (!this.cursor.color) return undefined;
|
||||
|
||||
return this.Pallete.getColor(this.palleteCtx.color);
|
||||
return this.Pallete.getColor(this.cursor.color);
|
||||
},
|
||||
|
||||
getColorFromHex: (hex: string) => {
|
||||
|
@ -306,8 +304,14 @@ export class Canvas extends EventEmitter<CanvasEvents> {
|
|||
},
|
||||
};
|
||||
|
||||
updatePallete(pallete: IPaletteContext) {
|
||||
this.palleteCtx = pallete;
|
||||
/**
|
||||
* Changes the cursor color as tracked by the Canvas instance
|
||||
*
|
||||
* @see Toolbar/Palette.tsx
|
||||
* @param color
|
||||
*/
|
||||
updateCursor(color?: number) {
|
||||
this.cursor.color = color;
|
||||
}
|
||||
|
||||
place(x: number, y: number) {
|
||||
|
|
|
@ -59,6 +59,11 @@ const KEYBINDS = enforceObjectType({
|
|||
key: "Escape",
|
||||
},
|
||||
],
|
||||
PICK_COLOR: [
|
||||
{
|
||||
key: "MCLICK",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
class KeybindManager_ extends EventEmitter<{
|
||||
|
@ -72,7 +77,11 @@ class KeybindManager_ extends EventEmitter<{
|
|||
passive: false,
|
||||
});
|
||||
document.addEventListener("keyup", this.handleKeyup);
|
||||
document.addEventListener("click", this.handleClick);
|
||||
document.addEventListener("click", this.handleClick); // only gets triggered for left click
|
||||
document.addEventListener("auxclick", (e) => {
|
||||
if (e.button === 0) return; // left button still triggers this
|
||||
this.handleClick(e);
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
|
|
|
@ -57,10 +57,6 @@ export interface IPosition {
|
|||
y: number;
|
||||
}
|
||||
|
||||
export interface IPaletteContext {
|
||||
color?: number;
|
||||
}
|
||||
|
||||
// other
|
||||
|
||||
export type Pixel = {
|
||||
|
|
Loading…
Reference in New Issue