Add a coordinate system and mouse tracking to the canvas
Adds X and Y axis labels to the canvas, displays mouse coordinates on hover, and updates the project documentation to reflect these new features. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 0385ea33-cde8-4bbd-8fce-8d192d30eb41 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/870d08ce-da3b-4822-9874-c2fe2b7628b1/0385ea33-cde8-4bbd-8fce-8d192d30eb41/zNDeQGA
This commit is contained in:
@@ -24,6 +24,7 @@ export function Canvas({
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [zoom, setZoom] = useState(1);
|
||||
const [pixelSize, setPixelSize] = useState(8);
|
||||
const [mouseCoords, setMouseCoords] = useState<{x: number, y: number} | null>(null);
|
||||
|
||||
// Create pixel map for O(1) lookup
|
||||
const pixelMap = new Map<string, string>();
|
||||
@@ -36,6 +37,14 @@ export function Canvas({
|
||||
onPixelClick(x, y);
|
||||
};
|
||||
|
||||
const handlePixelMouseEnter = (x: number, y: number) => {
|
||||
setMouseCoords({ x, y });
|
||||
};
|
||||
|
||||
const handlePixelMouseLeave = () => {
|
||||
setMouseCoords(null);
|
||||
};
|
||||
|
||||
const handleZoomIn = () => {
|
||||
setZoom(prev => Math.min(prev * 1.2, 3));
|
||||
};
|
||||
@@ -67,11 +76,49 @@ export function Canvas({
|
||||
className="w-full h-full overflow-auto p-8"
|
||||
data-testid="canvas-container"
|
||||
>
|
||||
<div
|
||||
className="grid mx-auto border border-gray-400 relative"
|
||||
style={canvasStyle}
|
||||
data-testid="pixel-canvas"
|
||||
>
|
||||
{/* Coordinate System Container */}
|
||||
<div className="relative inline-block">
|
||||
{/* Top X-axis coordinates */}
|
||||
<div className="flex ml-8 mb-1">
|
||||
{Array.from({ length: Math.ceil(canvasWidth / 10) }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="text-xs text-gray-400 text-center"
|
||||
style={{
|
||||
width: `${10 * pixelSize}px`,
|
||||
fontSize: `${Math.max(8, pixelSize * 0.8)}px`
|
||||
}}
|
||||
>
|
||||
{i * 10}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Canvas with left Y-axis coordinates */}
|
||||
<div className="flex">
|
||||
{/* Left Y-axis coordinates */}
|
||||
<div className="flex flex-col mr-1">
|
||||
{Array.from({ length: Math.ceil(canvasHeight / 10) }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="text-xs text-gray-400 flex items-center justify-end"
|
||||
style={{
|
||||
height: `${10 * pixelSize}px`,
|
||||
width: '24px',
|
||||
fontSize: `${Math.max(8, pixelSize * 0.8)}px`
|
||||
}}
|
||||
>
|
||||
{i * 10}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Main Canvas */}
|
||||
<div
|
||||
className="grid border border-gray-400 relative"
|
||||
style={canvasStyle}
|
||||
data-testid="pixel-canvas"
|
||||
>
|
||||
{Array.from({ length: canvasHeight }, (_, y) =>
|
||||
Array.from({ length: canvasWidth }, (_, x) => {
|
||||
const pixelColor = pixelMap.get(`${x},${y}`) || "#FFFFFF";
|
||||
@@ -88,6 +135,8 @@ export function Canvas({
|
||||
height: `${pixelSize}px`
|
||||
}}
|
||||
onClick={() => handlePixelClick(x, y)}
|
||||
onMouseEnter={() => handlePixelMouseEnter(x, y)}
|
||||
onMouseLeave={handlePixelMouseLeave}
|
||||
data-testid={`pixel-${x}-${y}`}
|
||||
data-x={x}
|
||||
data-y={y}
|
||||
@@ -95,9 +144,26 @@ export function Canvas({
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Coordinate Info Display */}
|
||||
<div className="absolute top-4 left-4 bg-panel-bg px-3 py-2 rounded-lg border border-gray-600">
|
||||
<div className="text-sm text-gray-300">
|
||||
Canvas: {canvasWidth} × {canvasHeight}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">
|
||||
Zoom: {Math.round(zoom * 100)}%
|
||||
</div>
|
||||
{mouseCoords && (
|
||||
<div className="text-xs text-green-400 mt-1">
|
||||
Mouse: ({mouseCoords.x}, {mouseCoords.y})
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Zoom Controls */}
|
||||
<div className="absolute bottom-4 right-4 flex flex-col space-y-2">
|
||||
<button
|
||||
|
||||
1
exports/canvas-2025-08-18T12-27-25-417Z.svg
Normal file
1
exports/canvas-2025-08-18T12-27-25-417Z.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg width="100" height="100" xmlns="http://www.w3.org/2000/svg"><rect width="100%" height="100%" fill="#FFFFFF"/><rect x="64" y="7" width="1" height="1" fill="#be0039"/><rect x="65" y="7" width="1" height="1" fill="#00ccc0"/></svg>
|
||||
|
After Width: | Height: | Size: 232 B |
@@ -45,10 +45,12 @@ Language: German (Deutsch) - User communicates in German and prefers responses i
|
||||
|
||||
**User Experience Features**
|
||||
- Interactive canvas with zoom and pan capabilities
|
||||
- Color palette with 16 predefined colors
|
||||
- Official r/place 2022 color palette with 32 authentic colors arranged in 8x4 grid
|
||||
- Coordinate system with X/Y axis labels showing every 10th position
|
||||
- Real-time mouse coordinate tracking and display
|
||||
- Cooldown system to prevent pixel spam
|
||||
- Recent placements tracking and display
|
||||
- Grid overlay toggle for precise pixel placement
|
||||
- Canvas size and zoom level information display
|
||||
- Toast notifications for user feedback
|
||||
|
||||
## External Dependencies
|
||||
|
||||
Reference in New Issue
Block a user