const canvas = document.getElementById('canvas'); const ctx = canvas.getContext('2d'); const defaultGridWidth = 16; const defaultGridHeight = 16; let gridWidth = defaultGridWidth; let gridHeight = defaultGridHeight; let cellSize = 16; let colorHistory = []; let currentColor = '#000000'; let grid = Array(gridWidth).fill().map(() => Array(gridHeight).fill(null)); let offsetX = 0; let offsetY = 0; // Event Listeners canvas.addEventListener('click', handleCanvasClick); document.getElementById('colorPicker').addEventListener('input', handleColorChange); document.getElementById('gridWidth').addEventListener('change', updateGridSize); document.getElementById('gridHeight').addEventListener('change', updateGridSize); document.getElementById('resetBtn').addEventListener('click', handleReset); document.getElementById('exportBtn').addEventListener('click', exportToPNG); window.addEventListener('keydown', handlePan); // Initialization resizeCanvas(); loadFromLocalStorage(); // Functions function initializeGrid() { grid = Array(gridWidth).fill().map(() => Array(gridHeight).fill(null)); } function resizeCanvas() { canvas.width = window.innerWidth; canvas.height = window.innerHeight; centerGrid(); drawGrid(); } function centerGrid() { offsetX = Math.max((canvas.width - (gridWidth * cellSize)) / 2, 0); offsetY = Math.max((canvas.height - (gridHeight * cellSize)) / 2, 0); } function drawGrid() { ctx.fillStyle = 'teal'; ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.strokeStyle = '#888888'; for (let x = 0; x < gridWidth; x++) { for (let y = 0; y < gridHeight; y++) { ctx.fillStyle = grid[x][y] || '#f7f7f7'; ctx.fillRect(x * cellSize + offsetX, y * cellSize + offsetY, cellSize, cellSize); ctx.strokeRect(x * cellSize + offsetX, y * cellSize + offsetY, cellSize, cellSize); } } } function addToColorHistory(color) { if (colorHistory.includes(color)) return; if (colorHistory.length >= 10) colorHistory.shift(); colorHistory.push(color); renderColorHistory(); } function renderColorHistory() { const historyDiv = document.getElementById('colorHistory'); historyDiv.innerHTML = ''; colorHistory.forEach(color => { const colorDiv = document.createElement('div'); colorDiv.style.backgroundColor = color; colorDiv.addEventListener('click', () => { currentColor = color; document.getElementById('colorPicker').value = color; }); historyDiv.appendChild(colorDiv); }); } function handleColorChange() { currentColor = document.getElementById('colorPicker').value; addToColorHistory(currentColor); saveToLocalStorage(); } function handleReset() { gridWidth = defaultGridWidth; gridHeight = defaultGridHeight; initializeGrid(); centerGrid(); drawGrid(); localStorage.removeItem('pixelArtConfig'); colorHistory = []; renderColorHistory(); document.getElementById('gridWidth').value = gridWidth; document.getElementById('gridHeight').value = gridHeight; alert("Grid reset, color history cleared, and local storage cleared."); } function handlePan(e) { const step = cellSize; if (e.key === 'ArrowUp') offsetY += step; if (e.key === 'ArrowDown') offsetY -= step; if (e.key === 'ArrowLeft') offsetX += step; if (e.key === 'ArrowRight') offsetX -= step; drawGrid(); } function updateGridSize() { gridWidth = parseInt(document.getElementById('gridWidth').value); gridHeight = parseInt(document.getElementById('gridHeight').value); initializeGrid(); centerGrid(); drawGrid(); saveToLocalStorage(); } function saveToLocalStorage() { const gridData = { gridWidth: gridWidth, gridHeight: gridHeight, cellSize: cellSize, colorHistory: colorHistory, currentColor: currentColor, grid: grid, }; localStorage.setItem('pixelArtConfig', JSON.stringify(gridData)); } function loadFromLocalStorage() { const savedData = localStorage.getItem('pixelArtConfig'); if (savedData) { const gridData = JSON.parse(savedData); gridWidth = gridData.gridWidth || 10; gridHeight = gridData.gridHeight || 10; cellSize = gridData.cellSize || 16; colorHistory = gridData.colorHistory || []; currentColor = gridData.currentColor || '#000000'; grid = gridData.grid || Array(gridWidth).fill().map(() => Array(gridHeight).fill(null)); document.getElementById('gridWidth').value = gridWidth; document.getElementById('gridHeight').value = gridHeight; document.getElementById('colorPicker').value = currentColor; centerGrid(); drawGrid(); } else { initializeGrid(); centerGrid(); drawGrid(); } } function exportToPNG() { const tempCanvas = document.createElement('canvas'); const tempCtx = tempCanvas.getContext('2d'); tempCanvas.width = gridWidth * cellSize; tempCanvas.height = gridHeight * cellSize; for (let x = 0; x < gridWidth; x++) { for (let y = 0; y < gridHeight; y++) { tempCtx.fillStyle = grid[x][y] || 'transparent'; tempCtx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize); } } tempCanvas.toBlob(blob => { const link = document.createElement('a'); link.href = URL.createObjectURL(blob); link.download = 'pixel-art.png'; link.click(); }); } function handleCanvasClick(e) { const rect = canvas.getBoundingClientRect(); const x = Math.floor((e.clientX - rect.left - offsetX) / cellSize); const y = Math.floor((e.clientY - rect.top - offsetY) / cellSize); if (x >= 0 && x < gridWidth && y >= 0 && y < gridHeight) { if (e.detail === 2) { // Double-click resets the cell grid[x][y] = null; } else { // Single-click paints the cell with the current color grid[x][y] = currentColor; } drawGrid(); saveToLocalStorage(); } }