const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const canvas = document.getElementById('toad');
canvas.width = viewportWidth;
canvas.height = viewportHeight;
const context = canvas.getContext('2d');
const cellSize = 50;
let shapes = [];
const drawLine = (x1, y1, x2, y2) => {
context.moveTo(x1, y1);
context.lineTo(x2, y2);
context.stroke();
};
const drawShape = (shape, x, y) => {
context.beginPath();
context.strokeStyle = '#2d2d2d';
context.fillStyle = '#2d2d2d';
const size = cellSize * 0.8;
const offset = (cellSize - size) / 2;
if (shape === 'square') {
context.rect(x + offset, y + offset, size, size);
} else if (shape === 'triangle') {
context.moveTo(x + cellSize / 2, y + offset);
context.lineTo(x + offset, y + size + offset);
context.lineTo(x + size + offset, y + size + offset);
context.closePath();
} else if (shape === 'circle') {
const radius = cellSize * 0.4;
const centerX = x + cellSize / 2;
const centerY = y + cellSize / 2;
context.arc(centerX, centerY, radius, 0, 2 * Math.PI);
} else if (shape === 'octagon') {
const cellCenterX = x + cellSize / 2;
const cellCenterY = y + cellSize / 2;
const sideLength = cellSize / (2 + Math.sqrt(2));
const angle = (2 * Math.PI) / 8;
context.moveTo(cellCenterX + sideLength * Math.cos(0), cellCenterY + sideLength * Math.sin(0));
[...Array(8).keys()].slice(1).forEach(i => {
const newX = cellCenterX + sideLength * Math.cos(i * angle);
const newY = cellCenterY + sideLength * Math.sin(i * angle);
context.lineTo(newX, newY);
});
context.closePath();
} else if (shape === 'pentagon') {
const cellCenterX = x + cellSize / 2;
const cellCenterY = y + cellSize / 2;
const sideLength = cellSize / (1 + Math.sqrt(5 / 2));
const angle = (2 * Math.PI) / 5;
context.moveTo(cellCenterX + sideLength * Math.cos(0), cellCenterY + sideLength * Math.sin(0));
[...Array(5).keys()].slice(1).forEach(i => {
const newX = cellCenterX + sideLength * Math.cos(i * angle);
const newY = cellCenterY + sideLength * Math.sin(i * angle);
context.lineTo(newX, newY);
});
context.closePath();
} else if (shape === 'diamond') {
context.moveTo(x + cellSize / 2, y + offset);
context.lineTo(x + offset, y + cellSize / 2);
context.lineTo(x + cellSize / 2, y + size + offset);
context.lineTo(x + size + offset, y + cellSize / 2);
context.closePath();
}
context.fill();
context.stroke();
shapes.push({ type: shape, x, y, color: '#2d2d2d' });
};
const createContextMenuOption = (shape) => {
const option = document.createElement('li');
option.textContent = shape;
option.style.cursor = 'pointer';
option.addEventListener('click', (event) => {
contextMenu.style.display = 'none';
const cellX = Math.floor(lastRightClick.x / cellSize) * cellSize;
const cellY = Math.floor(lastRightClick.y / cellSize) * cellSize;
drawShape(shape.toLowerCase(), cellX, cellY);
});
if (shape === 'Nope') {
option.style.color = 'lightcoral';
}
return option;
};
const contextMenu = document.createElement('ul');
contextMenu.id = 'context-menu';
contextMenu.style.display = 'none';
contextMenu.style.position = 'fixed';
contextMenu.style.listStyle = 'none';
contextMenu.style.lineHeight = '1.25';
contextMenu.style.padding = '10px';
contextMenu.style.fontSize = '18px';
contextMenu.style.backgroundColor = 'white';
contextMenu.style.border = '1px solid black';
['Square', 'Triangle', 'Circle', 'Octagon', 'Pentagon', 'Diamond', 'Nope'].forEach(shape => {
const option = createContextMenuOption(shape);
option.className = 'context-menu-item';
contextMenu.appendChild(option);
}); // I mean, realistically shape should be label, but I got this far...so Nope is gonna be a shape
document.body.appendChild(contextMenu);
let lastRightClick = { x: 0, y: 0 };
canvas.addEventListener('click', (event) => {
const cellX = Math.floor(event.clientX / cellSize) * cellSize;
const cellY = Math.floor(event.clientY / cellSize) * cellSize;
const clickedShape = shapes.find(shape => shape.x === cellX && shape.y === cellY);
if (!clickedShape) {
lastRightClick = { x: event.clientX, y: event.clientY };
contextMenu.style.display = 'block';
contextMenu.style.left = `${event.clientX}px`;
contextMenu.style.top = `${event.clientY}px`;
}
});
const removeShape = (x, y) => {
shapes = shapes.filter(shape => !(shape.x === x && shape.y === y));
drawGrid();
context.fillStyle = '#f0f0f0';
context.fillRect(x, y, cellSize, cellSize);
}
const drawGrid = () => {
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = '#f0f0f0';
context.fillRect(0, 0, canvas.width, canvas.height);
context.strokeStyle = 'white';
for (let x = 0; x < Math.ceil(viewportWidth / cellSize); x++) {
drawLine(x * cellSize, 0, x * cellSize, viewportHeight);
}
for (let y = 0; y < Math.ceil(viewportHeight / cellSize); y++) {
drawLine(0, y * cellSize, viewportWidth, y * cellSize);
}
shapes.forEach(shape => {
drawShape(shape.type, shape.x, shape.y);
});
}
let beatCounter = 0;
window.addEventListener('keydown', (event) => {
if (event.key === ' ' || event.key === 'Enter') {
beatCounter++;
console.log(`Beat: ${beatCounter}`);
}
});
canvas.addEventListener('dblclick', (event) => {
const cellX = Math.floor(event.clientX / cellSize) * cellSize;
const cellY = Math.floor(event.clientY / cellSize) * cellSize;
removeShape(cellX, cellY);
});
drawGrid();