pages/draw/index.html
2025-04-14 15:55:39 -04:00

273 lines
8.1 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MilkNet | Draw</title>
<link id="favicon" rel="icon" href="/assets/img/milk.png" type="image/x-icon">
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
display: flex;
justify-content: flex-start;
align-items: center;
height: 100vh;
background-color: #f5f5f5;
font-family: 'Segoe UI', sans-serif;
}
#drawingCanvas {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
cursor: crosshair;
}
.controls {
position: fixed;
top: 20px;
right: 20px;
background-color: #fff;
border: 2px solid #ccc;
padding: 20px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
width: 250px;
display: flex;
flex-direction: column;
justify-content: space-between;
height: calc(100vh - 40px);
font-family: 'Segoe UI', sans-serif;
}
.controls label {
margin-top: 10px;
display: block;
font-size: 16px;
}
.controls input[type="color"],
.controls input[type="range"],
.controls select {
width: 100%;
margin: 5px 0;
}
.controls button {
margin-top: 10px;
display: block;
width: 100%;
padding: 10px;
background-color: #000;
color: white;
font-size: 18px;
border: none;
cursor: pointer;
transition: background-color 0.3s;
}
.controls button:hover {
background-color: #333;
}
#shapeSelector {
display: none;
}
</style>
</head>
<body>
<canvas id="drawingCanvas"></canvas>
<div class="controls">
<div>
<label for="toolSelector">Tool</label>
<select id="toolSelector">
<option value="brush">Brush</option>
<option value="rainbow">Rainbow Brush</option>
<option value="eraser">Eraser</option>
<option value="shape">Shape</option>
</select>
<label for="shapeSelector">Shape</label>
<select id="shapeSelector">
<option value="square">Square</option>
<option value="circle">Circle</option>
<option value="triangle">Triangle</option>
</select>
<label for="colorPicker">Color</label>
<input type="color" id="colorPicker" value="#000000">
<label for="brushSize">Thickness</label>
<input type="range" id="brushSize" min="1" max="50" value="5">
<button id="undoButton">Undo</button>
<button id="redoButton">Redo</button>
</div>
<button id="clearButton">Clear</button>
</div>
<script>
const canvas = document.getElementById('drawingCanvas');
const ctx = canvas.getContext('2d');
const clearButton = document.getElementById('clearButton');
const colorPicker = document.getElementById('colorPicker');
const brushSize = document.getElementById('brushSize');
const toolSelector = document.getElementById('toolSelector');
const shapeSelector = document.getElementById('shapeSelector');
const undoButton = document.getElementById('undoButton');
const redoButton = document.getElementById('redoButton');
let isDrawing = false;
let lastX = 0, lastY = 0;
let startX = 0, startY = 0;
let previewCanvas, previewCtx;
let hue = 0;
let currentTool = 'brush';
let currentShape = 'square';
const undoStack = [];
const redoStack = [];
function saveState() {
undoStack.push(canvas.toDataURL());
redoStack.length = 0;
}
function restoreState(stackFrom, stackTo) {
if (stackFrom.length === 0) return;
stackTo.push(canvas.toDataURL());
const img = new Image();
img.src = stackFrom.pop();
img.onload = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, 0, 0);
};
}
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resizeCanvas);
resizeCanvas();
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
function getPosition(e) {
if (e.touches && e.touches.length > 0) {
return { x: e.touches[0].clientX, y: e.touches[0].clientY };
} else {
return { x: e.clientX, y: e.clientY };
}
}
function startDrawing(e) {
const pos = getPosition(e);
isDrawing = true;
startX = lastX = pos.x;
startY = lastY = pos.y;
if (currentTool !== 'shape') saveState();
}
function stopDrawing(e) {
if (!isDrawing) return;
isDrawing = false;
if (currentTool === 'shape') {
const pos = getPosition(e);
drawShape(startX, startY, pos.x, pos.y, true);
saveState();
}
}
function draw(e) {
const pos = getPosition(e);
if (currentTool === 'shape' && isDrawing) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
restorePreview();
drawShape(startX, startY, pos.x, pos.y, false);
return;
}
if (!isDrawing) return;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(pos.x, pos.y);
if (currentTool === 'rainbow') {
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
hue = (hue + 1) % 360;
} else if (currentTool === 'eraser') {
ctx.strokeStyle = '#ffffff';
} else {
ctx.strokeStyle = colorPicker.value;
}
ctx.lineWidth = brushSize.value;
ctx.stroke();
lastX = pos.x;
lastY = pos.y;
}
function drawShape(x1, y1, x2, y2, finalDraw) {
if (finalDraw) restorePreview();
ctx.fillStyle = colorPicker.value;
ctx.lineWidth = brushSize.value;
ctx.beginPath();
if (currentShape === 'square') {
const width = x2 - x1;
const height = y2 - y1;
ctx.fillRect(x1, y1, width, height);
} else if (currentShape === 'circle') {
const radius = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2) / 2;
ctx.arc((x1 + x2) / 2, (y1 + y2) / 2, radius, 0, Math.PI * 2);
ctx.fill();
} else if (currentShape === 'triangle') {
ctx.moveTo((x1 + x2) / 2, y1);
ctx.lineTo(x1, y2);
ctx.lineTo(x2, y2);
ctx.closePath();
ctx.fill();
}
}
function restorePreview() {
const img = new Image();
img.src = canvas.toDataURL();
img.onload = () => ctx.drawImage(img, 0, 0);
}
canvas.addEventListener('mousedown', startDrawing);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mouseup', stopDrawing);
canvas.addEventListener('mouseout', stopDrawing);
canvas.addEventListener('touchstart', startDrawing);
canvas.addEventListener('touchmove', draw);
canvas.addEventListener('touchend', stopDrawing);
colorPicker.addEventListener('input', (e) => ctx.strokeStyle = e.target.value);
brushSize.addEventListener('input', (e) => ctx.lineWidth = e.target.value);
toolSelector.addEventListener('change', (e) => {
currentTool = e.target.value;
shapeSelector.style.display = currentTool === 'shape' ? 'block' : 'none';
});
shapeSelector.addEventListener('change', (e) => currentShape = e.target.value);
undoButton.addEventListener('click', () => restoreState(undoStack, redoStack));
redoButton.addEventListener('click', () => restoreState(redoStack, undoStack));
clearButton.addEventListener('click', () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
saveState();
});
</script>
</body>
</html>