Add draggable preview and keep 30 histories
This commit is contained in:
+68
-2
@@ -156,8 +156,18 @@ export default function Home() {
|
||||
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
||||
const cropCanvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const canvasRef = useRef<HTMLCanvasElement | null>(null);
|
||||
const patternStageRef = useRef<HTMLDivElement | null>(null);
|
||||
const cropPreviewRef = useRef<HTMLDivElement | null>(null);
|
||||
const cropDragRef = useRef<{ pointerId: number; x: number; y: number; cropX: number; cropY: number } | null>(null);
|
||||
const patternDragRef = useRef<{
|
||||
pointerId: number;
|
||||
x: number;
|
||||
y: number;
|
||||
scrollLeft: number;
|
||||
scrollTop: number;
|
||||
moved: boolean;
|
||||
} | null>(null);
|
||||
const suppressCanvasClickRef = useRef(false);
|
||||
|
||||
useEffect(() => {
|
||||
const saved = localStorage.getItem("bead-pattern-history");
|
||||
@@ -362,7 +372,50 @@ export default function Home() {
|
||||
});
|
||||
};
|
||||
|
||||
const handlePatternPointerDown = (event: React.PointerEvent<HTMLCanvasElement>) => {
|
||||
if (event.button !== 0) return;
|
||||
const stage = patternStageRef.current;
|
||||
if (!stage) return;
|
||||
stage.setPointerCapture(event.pointerId);
|
||||
patternDragRef.current = {
|
||||
pointerId: event.pointerId,
|
||||
x: event.clientX,
|
||||
y: event.clientY,
|
||||
scrollLeft: stage.scrollLeft,
|
||||
scrollTop: stage.scrollTop,
|
||||
moved: false,
|
||||
};
|
||||
};
|
||||
|
||||
const handlePatternPointerMove = (event: React.PointerEvent<HTMLCanvasElement>) => {
|
||||
const stage = patternStageRef.current;
|
||||
const drag = patternDragRef.current;
|
||||
if (!stage || !drag || drag.pointerId !== event.pointerId) return;
|
||||
const deltaX = event.clientX - drag.x;
|
||||
const deltaY = event.clientY - drag.y;
|
||||
if (!drag.moved && Math.hypot(deltaX, deltaY) < 5) return;
|
||||
drag.moved = true;
|
||||
stage.classList.add("is-dragging");
|
||||
stage.scrollLeft = drag.scrollLeft - deltaX;
|
||||
stage.scrollTop = drag.scrollTop - deltaY;
|
||||
setHoveredPixel(null);
|
||||
};
|
||||
|
||||
const handlePatternPointerUp = (event: React.PointerEvent<HTMLCanvasElement>) => {
|
||||
const stage = patternStageRef.current;
|
||||
const drag = patternDragRef.current;
|
||||
if (!drag || drag.pointerId !== event.pointerId) return;
|
||||
suppressCanvasClickRef.current = drag.moved;
|
||||
patternDragRef.current = null;
|
||||
stage?.classList.remove("is-dragging");
|
||||
if (stage?.hasPointerCapture(event.pointerId)) stage.releasePointerCapture(event.pointerId);
|
||||
};
|
||||
|
||||
const handleCanvasClick = (event: React.MouseEvent<HTMLCanvasElement>) => {
|
||||
if (suppressCanvasClickRef.current) {
|
||||
suppressCanvasClickRef.current = false;
|
||||
return;
|
||||
}
|
||||
const canvas = canvasRef.current;
|
||||
if (!canvas) return;
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
@@ -499,9 +552,22 @@ export default function Home() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="canvas-stage">
|
||||
<div
|
||||
className="canvas-stage"
|
||||
ref={patternStageRef}
|
||||
>
|
||||
<div className="canvas-wrap">
|
||||
<canvas ref={canvasRef} onClick={handleCanvasClick} onMouseMove={handleCanvasMove} onMouseLeave={() => setHoveredPixel(null)} aria-label="转换后的拼豆像素图,点击格子可选择颜色" />
|
||||
<canvas
|
||||
ref={canvasRef}
|
||||
onPointerDown={handlePatternPointerDown}
|
||||
onPointerMove={handlePatternPointerMove}
|
||||
onPointerUp={handlePatternPointerUp}
|
||||
onPointerCancel={handlePatternPointerUp}
|
||||
onClick={handleCanvasClick}
|
||||
onMouseMove={handleCanvasMove}
|
||||
onMouseLeave={() => setHoveredPixel(null)}
|
||||
aria-label="转换后的拼豆像素图,可拖动查看,轻点格子选择颜色"
|
||||
/>
|
||||
{hoveredPixel && <div className="pixel-tooltip" style={{ left: hoveredPixel.left, top: hoveredPixel.top }}>
|
||||
<span className="tooltip-swatch" style={{ backgroundColor: hoveredPixel.color.hex }} />
|
||||
<strong>第 {hoveredPixel.row} 行 · 第 {hoveredPixel.column} 列</strong>
|
||||
|
||||
Reference in New Issue
Block a user