diff options
-rw-r--r-- | js/toadmode/APL386.ttf | bin | 0 -> 203668 bytes | |||
-rw-r--r-- | js/toadmode/index.html | 6 | ||||
-rw-r--r-- | js/toadmode/toad.js | 145 |
3 files changed, 111 insertions, 40 deletions
diff --git a/js/toadmode/APL386.ttf b/js/toadmode/APL386.ttf new file mode 100644 index 0000000..5e3a338 --- /dev/null +++ b/js/toadmode/APL386.ttf Binary files differdiff --git a/js/toadmode/index.html b/js/toadmode/index.html index 7d1fb17..6a0696e 100644 --- a/js/toadmode/index.html +++ b/js/toadmode/index.html @@ -5,10 +5,16 @@ <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>toad mode</title> <style> + /* https://github.com/abrudz/APL386 */ + @font-face {font-family: 'APL386';src: url('APL386.ttf');} + /* https://shantellsans.com/process */ + @import url('https://fonts.googleapis.com/css2?family=Shantell+Sans&display=swap'); body { margin: 0; padding: 0; background-color: #000; + font-family: 'APL386', monospace; + /* font-family: 'Shantell Sans', sans-serif; */ } canvas { display: block; diff --git a/js/toadmode/toad.js b/js/toadmode/toad.js index 73d4cbf..3b7ba84 100644 --- a/js/toadmode/toad.js +++ b/js/toadmode/toad.js @@ -7,11 +7,8 @@ canvas.height = viewportHeight; const context = canvas.getContext('2d'); -context.fillStyle = '#f0f0f0'; -context.fillRect(0, 0, canvas.width, canvas.height); - const gridSize = 50; -context.strokeStyle = 'white'; +let shapes = []; const drawLine = (x1, y1, x2, y2) => { context.moveTo(x1, y1); @@ -19,45 +16,61 @@ const drawLine = (x1, y1, x2, y2) => { context.stroke(); }; -for (let x = 0; x <= viewportWidth; x += gridSize) { - drawLine(x, 0, x, viewportHeight); -} - -for (let y = 0; y <= viewportHeight; y += gridSize) { - drawLine(0, y, viewportWidth, y); -} - -const contextMenu = document.createElement('ul'); -contextMenu.id = 'context-menu'; -contextMenu.style.display = 'none'; -contextMenu.style.position = 'fixed'; -contextMenu.style.listStyle = 'none'; -contextMenu.style.padding = '10px'; -contextMenu.style.backgroundColor = 'white'; -contextMenu.style.border = '1px solid black'; - const drawShape = (shape, x, y) => { context.beginPath(); context.strokeStyle = '#2d2d2d'; context.fillStyle = '#2d2d2d'; + const size = gridSize * 0.8; + const offset = (gridSize - size) / 2; if (shape === 'square') { - context.rect(x, y, gridSize, gridSize); - context.fill(); + context.rect(x + offset, y + offset, size, size); } else if (shape === 'triangle') { - context.moveTo(x, y); - context.lineTo(x + gridSize, y); - context.lineTo(x + gridSize / 2, y + gridSize); + context.moveTo(x + gridSize / 2, y + offset); + context.lineTo(x + offset, y + size + offset); + context.lineTo(x + size + offset, y + size + offset); context.closePath(); - context.fill(); } else if (shape === 'circle') { - context.arc(x + gridSize / 2, y + gridSize / 2, gridSize / 2, 0, 2 * Math.PI); - context.fill(); + const radius = gridSize * 0.4; + const centerX = x + gridSize / 2; + const centerY = y + gridSize / 2; + context.arc(centerX, centerY, radius, 0, 2 * Math.PI); + } else if (shape === 'octagon') { + const cellCenterX = x + gridSize / 2; + const cellCenterY = y + gridSize / 2; + const sideLength = gridSize / (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 + gridSize / 2; + const cellCenterY = y + gridSize / 2; + const sideLength = gridSize / (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 + gridSize / 2, y + offset); + context.lineTo(x + offset, y + gridSize / 2); + context.lineTo(x + gridSize / 2, y + size + offset); + context.lineTo(x + size + offset, y + gridSize / 2); + context.closePath(); } + context.fill(); context.stroke(); shapes.push({ type: shape, x, y, color: '#2d2d2d' }); }; -['Square', 'Triangle', 'Circle'].forEach(shape => { +const createContextMenuOption = (shape) => { const option = document.createElement('li'); option.textContent = shape; option.style.cursor = 'pointer'; @@ -67,6 +80,25 @@ const drawShape = (shape, x, y) => { const cellY = Math.floor(lastRightClick.y / gridSize) * gridSize; 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); contextMenu.appendChild(option); }); @@ -74,16 +106,49 @@ document.body.appendChild(contextMenu); let lastRightClick = { x: 0, y: 0 }; -canvas.addEventListener('contextmenu', (event) => { - event.preventDefault(); - lastRightClick = { x: event.clientX, y: event.clientY }; - contextMenu.style.display = 'block'; - contextMenu.style.left = `${event.clientX}px`; - contextMenu.style.top = `${event.clientY}px`; +canvas.addEventListener('click', (event) => { + const cellX = Math.floor(event.clientX / gridSize) * gridSize; + const cellY = Math.floor(event.clientY / gridSize) * gridSize; + 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`; + } }); -let shapes = []; +const removeShape = (x, y) => { + shapes = shapes.filter(shape => !(shape.x === x && shape.y === y)); + redrawGrid(); + context.fillStyle = '#f0f0f0'; + context.fillRect(x, y, gridSize, gridSize); +} + +const redrawGrid = () => { + context.clearRect(0, 0, canvas.width, canvas.height); + + context.fillStyle = '#f0f0f0'; + context.fillRect(0, 0, canvas.width, canvas.height); + + context.strokeStyle = 'white'; + [...Array(Math.ceil(viewportWidth / gridSize)).keys()].forEach(x => { + drawLine(x * gridSize, 0, x * gridSize, viewportHeight); + }); + + [...Array(Math.ceil(viewportHeight / gridSize)).keys()].forEach(y => { + drawLine(0, y * gridSize, viewportWidth, y * gridSize); + }); + + shapes.forEach(shape => { + drawShape(shape.type, shape.x, shape.y); + }); +} + +canvas.addEventListener('dblclick', (event) => { + const cellX = Math.floor(event.clientX / gridSize) * gridSize; + const cellY = Math.floor(event.clientY / gridSize) * gridSize; + removeShape(cellX, cellY); +}); -window.addEventListener('click', () => { - contextMenu.style.display = 'none'; -}); \ No newline at end of file +redrawGrid(); |