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();
}
}