Newer
Older
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import { Canvas } from "../lib/canvas";
import { useAppContext } from "../contexts/AppContext";
import { PanZoomWrapper } from "@sc07-canvas/lib/src/renderer";
import { RendererContext } from "@sc07-canvas/lib/src/renderer/RendererContext";
import { ViewportMoveEvent } from "@sc07-canvas/lib/src/renderer/PanZoom";
import throttle from "lodash.throttle";
import { IPosition } from "@sc07-canvas/lib/src/net";
import { Template } from "./Templating/Template";
import { Template as TemplateCl } from "../lib/template";
import { IRouterData, Router } from "../lib/router";
import { KeybindManager } from "../lib/keybinds";

Grant
committed
import { HeatmapOverlay } from "./Overlay/HeatmapOverlay";
import { useTemplateContext } from "../contexts/TemplateContext";
import { PixelPulses } from "./Overlay/PixelPulses";
import { CanvasUtils } from "../lib/canvas.utils";
const { config } = useAppContext();
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
const getInitialPosition = useCallback<
(useCssZoom: boolean) =>
| {
x: number;
y: number;
zoom?: number;
}
| undefined
>(
(useCssZoom) => {
const router = Router.get().canvas;
if (!router) return undefined;
if (!config) {
console.warn("getInitialPosition called with no config");
return undefined;
}
const { transformX, transformY } = CanvasUtils.canvasToPanZoomTransform(
router.x,
router.y,
config.canvas.size,
useCssZoom
);
return {
x: transformX,
y: transformY,
zoom: router.zoom,
};
},
[config]
);
<PanZoomWrapper initialPosition={getInitialPosition}>

Grant
committed
<HeatmapOverlay />
{config && <Template />}
const Cursor = () => {
const { cursor } = useAppContext();
const [color, setColor] = useState<string>();
useEffect(() => {
if (typeof cursor.color === "number") {
const color = Canvas.instance?.Pallete.getColor(cursor.color);
setColor(color?.hex);
} else {
setColor(undefined);
}
}, [setColor, cursor.color]);
if (!color) return <></>;
return (
<div
className="noselect"
style={{
position: "absolute",
top: cursor.y,
left: cursor.x,
backgroundColor: "#" + color,
width: "1px",
height: "1px",
opacity: 0.5,
}}
></div>
);
};
const canvasRef = useRef<HTMLCanvasElement | null>();
const canvas = useRef<Canvas>();
const { config, setCanvasPosition, setCursor, setPixelWhois } =
useAppContext();
const {
x: templateX,
y: templateY,
enable: templateEnable,
} = useTemplateContext();
/**
* Is the canvas coordinate within the bounds of the canvas?
*/
const isCoordInCanvas = useCallback(
(x: number, y: number): boolean => {
if (!canvas.current) {
console.warn(
"[CanvasWrapper#isCoordInCanvas] canvas instance does not exist"
);
}
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
if (canvas.current.hasConfig()) {
const {
canvas: {
size: [width, height],
},
} = canvas.current.getConfig();
if (x >= width || y >= height) return false; // out of bounds
} else {
// although this should never happen, log it
console.warn(
"[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"
);
}
const [x, y] = canvas.current.screenToPos(clientX, clientY);
if (!isCoordInCanvas(x, y)) return; // out of bounds
// .......
// .......
// .......
// ...x...
// .......
// .......
// .......
const surrounding = canvas.current.getSurroundingPixels(x, y, 3);
setPixelWhois({ x, y, surrounding });
const getTemplatePixel = useCallback(
(x: number, y: number) => {
if (!templateEnable) return;
if (x < templateX || y < templateY) return;
x -= templateX;
y -= templateY;
return TemplateCl.instance.getPixel(x, y);
},
[templateX, templateY]
);
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
let pixelColor = -1;
const templatePixel = getTemplatePixel(x, y);
if (templatePixel) {
pixelColor =
canvas.current.Pallete.getColorFromHex(templatePixel.slice(1))?.id ||
-1;
}
if (pixelColor === -1) {
pixelColor = canvas.current.getPixel(x, y)?.color || -1;
}
if (pixelColor === -1) {
return;
}
// no need to use canvas#setCursor as Palette.tsx already does that
setCursor((v) => ({
...v,
useEffect(() => {
if (!canvasRef.current) return;
canvas.current = new Canvas(canvasRef.current!, PanZoom);
canvas.current.on("canvasReady", () => {
console.log("[CanvasWrapper] received canvasReady");
});
KeybindManager.on("PIXEL_WHOIS", handlePixelWhois);
KeybindManager.off("PIXEL_WHOIS", handlePixelWhois);
useEffect(() => {
Router.PanZoom = PanZoom;
}, [PanZoom]);
if (!canvas.current) {
console.warn("canvas isntance doesn't exist");
return;
}
const handleCursorPos = throttle((pos: IPosition) => {
if (!canvas.current?.hasConfig() || !config) {
console.warn("handleCursorPos has no config");
return;
}
if (
pos.x < 0 ||
pos.y < 0 ||
pos.x > config.canvas.size[0] ||
pos.y > config.canvas.size[1]
) {
setCursor((v) => ({
...v,
x: undefined,
y: undefined,
}));
} else {
// fixes not passing the current value
setCursor((v) => ({
...v,
x: pos.x,
y: pos.y,
}));
}
}, 1);
canvas.current.on("cursorPos", handleCursorPos);
return () => {
canvas.current!.off("cursorPos", handleCursorPos);
};
useEffect(() => {
if (!canvas.current) {
console.warn("canvasinner config received but no canvas instance");
return;
}
if (!config) {
console.warn("canvasinner config received falsey");
return;
}
console.log("[CanvasInner] config updated, informing canvas instance");
canvas.current.loadConfig(config);
}, [config]);
const handleNavigate = useCallback(
(data: IRouterData) => {
const position = canvas.current!.canvasToPanZoomTransform(
data.canvas.x,
data.canvas.y
);
PanZoom.setPosition(
{
x: position.transformX,
y: position.transformY,
zoom: data.canvas.zoom || 0, // TODO: fit canvas to viewport instead of defaulting
},
{ suppressEmit: true }
);
},
[PanZoom]
);
useEffect(() => {
// if (!config?.canvas || !canvasRef.current) return;
// const canvas = canvasRef.current!;
// const canvasInstance = new Canvas(canvas, PanZoom);
const initAt = Date.now();
// initial position from Router is setup in <CanvasWrapper>
const handleViewportMove = (state: ViewportMoveEvent) => {
if (Date.now() - initAt < 60 * 1000) {
console.debug(
"[CanvasWrapper] handleViewportMove called soon after init",
Date.now() - initAt
);
}
if (canvas.current) {
const pos = canvas.current?.panZoomTransformToCanvas();
setCanvasPosition({
x: pos.canvasX,
y: pos.canvasY,
zoom: state.scale >> 0,
});
} else {
console.warn(
"[CanvasWrapper] handleViewportMove has no canvas instance"
);
}
PanZoom.addListener("viewportMove", handleViewportMove);
PanZoom.removeListener("viewportMove", handleViewportMove);
return (
<canvas
id="board"
width="1000"
height="1000"
className="pixelate"