From 9c057113b594d28734f2e980331e54bfe8063a9e Mon Sep 17 00:00:00 2001 From: Gregory Leeman Date: Sun, 11 Aug 2024 16:31:18 +0100 Subject: [PATCH] lazygit --- archive/temp.js | 1 - render.js | 237 ++++++++++++++++++++++++++++++++++++++++-------- style.css | 95 ++++++++++++++++++- 3 files changed, 293 insertions(+), 40 deletions(-) diff --git a/archive/temp.js b/archive/temp.js index 883081d..5076e70 100644 --- a/archive/temp.js +++ b/archive/temp.js @@ -37,7 +37,6 @@ function createPuck(c) { dragHandle.innerHTML = ''; puckMenu.appendChild(dragHandle); - well.addEventListener('mousedown', (e) => { let isMixing = true; let startX = e.clientX; diff --git a/render.js b/render.js index bfd217e..aadbb71 100644 --- a/render.js +++ b/render.js @@ -9,12 +9,11 @@ const canvasContainer = document.getElementById('canvas-container'); const brushPreview = document.getElementById('brush-preview'); const canvas = document.getElementById('canvas'); +// canvas.style.imageRendering = 'pixelated'; const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.mozImageSmoothingEnabled = false; -ctx.fillStyle = 'white'; -ctx.fillRect(0, 0, canvas.width, canvas.height); canvas.width = 800; canvas.height = 600; @@ -31,6 +30,7 @@ let zoom = 1; let brushSize = 5; let dBrushSize = 0.5; let maxBrushSize = 500; +let backgroundColor = 'rgb(255, 255, 255)'; let color = 'rgb(0, 0, 0)'; let tool @@ -247,7 +247,7 @@ canvasArea.addEventListener('mousedown', (e) => { isMouseDown = true; if ( - tool === 'draw' || + tool === 'brush' || tool === 'content-move' || tool === 'resize' || tool === 'zoom' || @@ -256,7 +256,7 @@ canvasArea.addEventListener('mousedown', (e) => { saveState(); } - if (tool === 'draw') { + if (tool === 'brush') { drawCircle(canvasStartX, canvasStartY); } else if (tool === 'bucket-fill') { floodFill(canvasStartX, canvasStartY, color); @@ -305,7 +305,7 @@ canvasArea.addEventListener('mousemove', (e) => { if (brushSize < 1) brushSize = 1; if (brushSize > maxBrushSize) brushSize = maxBrushSize; startX = endX; - } else if (tool === 'draw') { + } else if (tool === 'brush') { drawLineWithCircles(canvasStartX, canvasStartY, canvasEndX, canvasEndY); canvasStartX = canvasEndX; @@ -313,6 +313,8 @@ canvasArea.addEventListener('mousemove', (e) => { } else if (tool === 'content-move') { ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.drawImage(tempCanvas, dX, dY); } else if (tool === 'move') { canvasContainer.style.left = dX + 'px'; @@ -332,6 +334,8 @@ canvasArea.addEventListener('mousemove', (e) => { canvas.style.width = newWidth * zoom + 'px'; canvas.style.height = newHeight * zoom + 'px'; ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.fillStyle = backgroundColor; + ctx.fillRect(0, 0, canvas.width, canvas.height); ctx.drawImage(tempCanvas, 0, 0); } } else if (tool === 'color-mix') { @@ -362,7 +366,7 @@ canvasArea.addEventListener('mousemove', (e) => { canvasArea.addEventListener('mouseup', (e) => { isMouseDown = false; - if (tool === 'draw') { + if (tool === 'brush') { ctx.closePath(); } else if (tool === 'resize') { canvasWidth = canvas.width; @@ -377,6 +381,7 @@ canvasArea.addEventListener('mouseup', (e) => { // mouseleave {{{ canvasArea.addEventListener('mouseleave', (e) => { + isMouseDown = false; brushPreview.style.display = 'none'; }); @@ -386,32 +391,49 @@ canvasArea.addEventListener('mouseleave', (e) => { var toolButtons = []; -function createToolButton(icon, buttonTool) { +function changeTool(toolName) { + toolButtons.forEach(button => button.button.classList.remove('active')); + toolButtons.find(button => button.name === toolName).button.classList.add('active'); + tool = toolName; + brushPreview.style.display = 'none'; + updateInfos(); +} + +function createToolButton(displayName, icon, toolName, jumpKey=undefined, temporaryKey=undefined) { const button = document.createElement('div'); button.classList.add('button'); button.classList.add('tool'); button.innerHTML = icon; - button.title = buttonTool; + button.title = displayName; button.addEventListener('click', () => { - buttons = document.getElementsByClassName('tool-button'); - toolButtons.forEach(button => button.button.classList.remove('active')); - button.classList.add('active'); - tool = buttonTool; - updateInfos(); + changeTool(toolName); }); + if (jumpKey) { + const jumpKeyHint = document.createElement('span'); + jumpKeyHint.className = 'jump-key-hint'; + jumpKeyHint.innerHTML = jumpKey; + button.appendChild(jumpKeyHint); + } + if (temporaryKey) { + const temporaryKeyHint = document.createElement('span'); + temporaryKeyHint.className = 'temporary-key-hint'; + temporaryKeyHint.innerHTML = temporaryKey; + button.appendChild(temporaryKeyHint); + } + toolBar.appendChild(button); return button; } -toolButtons.push({'name': 'draw', 'button': createToolButton('', 'draw')}); -toolButtons.push({'name': 'content-move', 'button': createToolButton('', 'content-move')}); -toolButtons.push({'name': 'move', 'button': createToolButton('', 'move')}); -toolButtons.push({'name': 'zoom', 'button': createToolButton('', 'zoom')}); -toolButtons.push({'name': 'resize', 'button': createToolButton('', 'resize')}); -toolButtons.push({'name': 'color-picker', 'button': createToolButton('', 'color-picker')}); -toolButtons.push({'name': 'color-mix', 'button': createToolButton('', 'color-mix')}); -toolButtons.push({'name': 'brush-size', 'button': createToolButton('', 'brush-size')}); -toolButtons.push({'name': 'bucket-fill', 'button': createToolButton('', 'bucket-fill')}); +toolButtons.push({'name': 'brush', 'button': createToolButton('Brush', '', 'brush', 'e', undefined)}); +toolButtons.push({'name': 'content-move', 'button': createToolButton('Move Content', '', 'content-move', 'h', undefined)}); +toolButtons.push({'name': 'move', 'button': createToolButton('Move Canvas', '', 'move', 'm', undefined)}); +toolButtons.push({'name': 'zoom', 'button': createToolButton('Zoom', '', 'zoom', 'z', undefined)}); +toolButtons.push({'name': 'resize', 'button': createToolButton('Resize', '', 'resize', 'r', undefined)}); +toolButtons.push({'name': 'color-picker', 'button': createToolButton('Color Picker', '', 'color-picker', 'a', undefined)}); +toolButtons.push({'name': 'color-mix', 'button': createToolButton('Color Mix', '', 'color-mix', 's', undefined)}); +toolButtons.push({'name': 'brush-size', 'button': createToolButton('Brush Size', '', 'brush-size', 'd', undefined)}); +toolButtons.push({'name': 'bucket-fill', 'button': createToolButton('Bucket Fill', '', 'bucket-fill', 'f', undefined)}); // }}} @@ -497,8 +519,8 @@ function createMenuButton(icon, name, clickFunction) { button.innerHTML = icon; button.title = name; if (clickFunction) { - button.addEventListener('click', (e) => { - clickFunction(e) + button.addEventListener('click', () => { + clickFunction() updateInfos(); }); } @@ -513,34 +535,127 @@ menuButtons.push(createMenuButton('', 'Flip V menuButtons.push(createMenuButton('', 'Undo', undo)); menuButtons.push(createMenuButton('', 'Redo', redo)); menuButtons.push(createMenuButton('', 'Clear', clearCanvas)); -menuButtons.push(createMenuButton('', 'Reset Zoom', resetZoom)); +menuButtons.push(createMenuButton('', 'Reset', resetZoom)); +menuButtons.push(createMenuButton('', 'Add Color', createPuck)); // }}} // pucks {{{ -function createPuck(c) { +function createPuck(c, editable=true) { + if (c === undefined) { + c = color; + } + const puck = document.createElement('div'); puck.className = 'puck'; puck.style.backgroundColor = c; - puck.addEventListener('click', () => { - color = c; + const selectHandle = document.createElement('div'); + selectHandle.className = 'select-handle'; + selectHandle.innerHTML = ''; + puck.appendChild(selectHandle); + + selectHandle.addEventListener('click', () => { + color = puck.style.backgroundColor; updateColorPreview(); updateInfos(); }); + if (editable) { + const updateHandle = document.createElement('div'); + updateHandle.className = 'update-handle'; + updateHandle.innerHTML = ''; + puck.appendChild(updateHandle); + + updateHandle.addEventListener('click', () => { + puck.style.backgroundColor = color; + }); + + const deleteHandle = document.createElement('div'); + deleteHandle.className = 'delete-handle'; + deleteHandle.innerHTML = ''; + puck.appendChild(deleteHandle); + + deleteHandle.addEventListener('click', () => { + console.log("test"); + puck.remove(); + }); + } + + puck.addEventListener('mousedown', (e) => { + let isMixing = true; + const startTime = Date.now(); // Record the time when the mouse is pressed + + // Interval to update the color based on time + const interval = setInterval(() => { + if (isMixing) { + const elapsedTime = Date.now() - startTime; + const t = Math.min(1, elapsedTime / 10000); + + const mixedColor = mixbox.lerp(color, puck.style.backgroundColor, t); + + color = mixedColor; + + updateColorPreview(); + updateInfos(); + } + }, 50); // Update every 50ms + + document.addEventListener('mouseup', onMouseUp); + + function onMouseUp() { + isMixing = false; + clearInterval(interval); // Stop the interval when the mouse is released + document.removeEventListener('mouseup', onMouseUp); + } + }); + + // puck.addEventListener('mousedown', (e) => { + // let isMixing = true; + // let startX = e.clientX; + // let startY = e.clientY; + + // document.addEventListener('mousemove', onMouseMove); + // document.addEventListener('mouseup', onMouseUp); + + // function onMouseMove(e) { + // if (isMixing) { + // const distance = Math.sqrt(Math.pow(e.clientX - startX, 2) + Math.pow(e.clientY - startY, 2)); + + // const t = Math.min(1, distance / 300); + + // const mixedColor = mixbox.lerp(color, puck.style.backgroundColor, t); + + // color = mixedColor; + + // startX = e.clientX; + // startY = e.clientY; + // updateColorPreview(); + // updateInfos(); + // } + // } + + // function onMouseUp() { + // isMixing = false; + // document.removeEventListener('mousemove', onMouseMove); + // document.removeEventListener('mouseup', onMouseUp); + // } + // }); + + menuBar.appendChild(puck); } -createPuck('rgb(255, 0, 0)'); -createPuck('rgb(0, 255, 0)'); -createPuck('rgb(0, 0, 255)'); -createPuck('rgb(255, 255, 0)'); -createPuck('rgb(255, 0, 255)'); -createPuck('rgb(0, 255, 255)'); -createPuck('rgb(0, 0, 0)'); -createPuck('rgb(255, 255, 255)'); +createPuck(c='rgb(0, 0, 0)', editable=false); +createPuck(c='rgb(255, 255, 255)', editale=false); +createPuck(c='rgb(0, 255, 0)', editale=false); +createPuck(c='rgb(0, 0, 255)', editale=false); +createPuck(c='rgb(255, 255, 0)', editale=false); +createPuck(c='rgb(255, 0, 0)', editale=false); +createPuck(c='rgb(255, 0, 255)', editale=false); +createPuck(c='rgb(0, 255, 255)', editale=false); + // }}} @@ -568,7 +683,6 @@ function createInfo(name, updateFunction) { return update; } -infos.push(createInfo('tool', function() { return tool; })); infos.push(createInfo('zoom', function() { var percent = zoom * 100; return percent.toFixed(0) + '%'; @@ -586,10 +700,59 @@ function updateInfos() { // }}} +// keybindings {{{ + +let keyDown = false; +let oldTool = tool; + +const toolBindings = [ + {'key': 'e', 'tool': 'brush', 'persistent': true}, + {'key': 'h', 'tool': 'content-move', 'persistent': true}, + {'key': 'm', 'tool': 'move', 'persistent': true}, + {'key': 'z', 'tool': 'zoom', 'persistent': true}, + {'key': 'r', 'tool': 'resize', 'persistent': true}, + {'key': 'a', 'tool': 'color-picker', 'persistent': false}, + {'key': 's', 'tool': 'color-mix', 'persistent': false}, + {'key': 'd', 'tool': 'brush-size', 'persistent': false}, +] + +const functionBindings = [ + {'key': 'u', 'function': undo}, + {'key': 'y', 'function': redo}, + {'key': 'backspace', 'function': clearCanvas}, +] + +document.addEventListener('keydown', (e) => { + if (keyDown) return; + + if (toolBindings.map(b => b.key).includes(e.key)) { + oldTool = tool; + keyDown = true; + changeTool(toolBindings.find(b => b.key === e.key).tool); + return; + } + + if (functionBindings.map(b => b.key).includes(e.key)) { + functionBindings.find(b => b.key === e.key).function(); + } +}); + +document.addEventListener('keyup', (e) => { + keyDown = false; + if (toolBindings.filter(b => !b.persistent).map(b => b.key).includes(e.key)) { + changeTool(oldTool); + } +}); + +// }}} + // start {{{ +ctx.fillStyle = backgroundColor; +ctx.fillRect(0, 0, canvas.width, canvas.height); updateInfos(); toolButtons[0]['button'].click(); +resetZoom(); // }}} diff --git a/style.css b/style.css index 27cf88a..0662bbb 100644 --- a/style.css +++ b/style.css @@ -15,6 +15,18 @@ body { height: 100vh; width: 100vw; font-family: 'VT323', monospace; + background-color: darkgray; +} + +#menu-bar, +#info-bar, +#tool-bar, +#layer-bar { + z-index: 2; +} + +#menu-bar { + justify-content: space-between; } #menu-bar, #info-bar { @@ -24,6 +36,7 @@ body { flex-direction: row; gap: 10px; justify-content: flex-start; + flex-wrap: wrap; } #menu-bar { @@ -53,7 +66,6 @@ body { } #canvas-area { - background-color: darkgray; flex-grow: 1; height: 100%; border: 1px solid; @@ -63,7 +75,7 @@ body { #canvas-container { position: absolute; border: 1px solid; - background-color: white; + z-index: -1; } @@ -72,6 +84,8 @@ body { } .button { + position: relative; + flex-shrink: 0; background-color: #ddd; border: 1px solid; border-radius: 2px; @@ -82,15 +96,92 @@ body { flex-direction: column; text-align: center; justify-content: center; + cursor: pointer; } .puck { + position: relative; + flex-shrink: 0; width: 30px; height: 30px; border: 1px solid; border-radius: 2px; } +.select-handle { + position: absolute; + bottom: 0; + right: 0; + font-size: .5em; + background-color: black; + color: white; + padding: 3px 0 1px 4px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + border-radius: 10px 0 0 0; + border-left: 1px solid white; + border-top: 1px solid white; + cursor: pointer; +} + +.update-handle { + position: absolute; + top: 0; + right: 0; + font-size: .5em; + background-color: black; + color: white; + padding: 1px 0 3px 4px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + border-radius: 0 0 0 10px; + border-left: 1px solid white; + border-bottom: 1px solid white; + cursor: pointer; +} + +.delete-handle { + position: absolute; + top: 0; + left: 0; + font-size: .5em; + background-color: black; + color: white; + padding: 1px 4px 3px 0; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + border-radius: 0 0 10px 0; + border-right: 1px solid white; + border-bottom: 1px solid white; + cursor: pointer; +} + +.jump-key-hint { + display: block; + height: 12px; + width: 8px; + line-height: 8px; + /* width: 12px; */ + position: absolute; + top: 0; + left: 0; + font-size: 1em; + /* padding: 2px 2px 2px 2px; */ + /* display: flex; */ + /* align-items: center; */ + justify-content: center; + text-align: center; + border-radius: 0 0 5px 0; + /* border-right: 1px solid; */ + /* border-bottom: 1px solid; */ +} + .button.active, .button:active { background-color: darkgray; }