您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Enhanced shape animations with more features and shapes.
// ==UserScript== // @name Drawaria Shape Animator 3.0 // @namespace http://tampermonkey.net/ // @version 3.0 // @description Enhanced shape animations with more features and shapes. // @author YourName // @match *://drawaria.online/* // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=drawaria.online // @grant none // ==/UserScript== (function () { 'use strict'; // CSS for the menu const style = document.createElement('style'); style.textContent = ` .menu { position: fixed; top: 10px; right: 10px; background-color: #333; color: #eee; padding: 10px; border-radius: 5px; z-index: 1000; box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); cursor: move; width: 300px; overflow-y: auto; max-height: 80vh; } .menu h1 { margin: 0 0 10px 0; font-size: 18px; text-align: center; } .menu label { display: block; margin-bottom: 5px; } .menu input[type="range"], .menu input[type="color"] { width: calc(100% - 10px); } .menu button { display: block; width: 100%; margin: 5px 0; padding: 8px; background-color: #555; color: #eee; border: none; border-radius: 3px; cursor: pointer; } .menu button:hover { background-color: #777; } .menu-toggle { position: absolute; top: 5px; right: 5px; background: none; border: none; color: #eee; font-size: 20px; cursor: pointer; } `; document.head.appendChild(style); // Function to send draw commands function sendDrawCommand(startX, startY, endX, endY, thickness, color) { const message = `42["drawcmd",0,[${startX},${startY},${endX},${endY},false,${0 - thickness},"${color}",0,0,{}]]`; try { sockets.forEach(socket => socket.send(message)); } catch (error) { console.error("Error sending draw command:", error); } } // Shape drawing functions function drawCircle(x, y, radius, color, thickness, fill = false) { const angleIncrement = (2 * Math.PI) / 32; if (fill) { // Fill Circle Logic Here (if supported) } for (let i = 0; i < 32; i++) { const angle1 = i * angleIncrement; const angle2 = (i + 1) * angleIncrement; const startX = x + radius * Math.cos(angle1); const startY = y + radius * Math.sin(angle1); const endX = x + radius * Math.cos(angle2); const endY = y + radius * Math.sin(angle2); sendDrawCommand(startX, startY, endX, endY, thickness, color); } } function drawPolygon(x, y, size, sides, color, thickness) { const angleIncrement = (2 * Math.PI) / sides; for (let i = 0; i < sides; i++) { const angle1 = i * angleIncrement; const angle2 = (i + 1) * angleIncrement; const startX = x + size * Math.cos(angle1); const startY = y + size * Math.sin(angle1); const endX = x + size * Math.cos(angle2); const endY = y + size * Math.sin(angle2); sendDrawCommand(startX, startY, endX, endY, thickness, color); } } function drawSpiral(x, y, maxRadius, turns, color, thickness) { const segments = 100; for (let i = 0; i <= segments; i++) { const angle = (i / segments) * turns * 2 * Math.PI; const radius = (i / segments) * maxRadius; const startX = x + radius * Math.cos(angle); const startY = y + radius * Math.sin(angle); if (i > 0) { sendDrawCommand(prevX, prevY, startX, startY, thickness, color); } prevX = startX; prevY = startY; } } // Store active shapes for undo/redo let actions = []; let redoActions = []; function recordAction(action) { actions.push(action); redoActions = []; } // Menu creation const menu = document.createElement('div'); menu.className = 'menu'; menu.innerHTML = `<h1>Drawaria Shape Animator</h1>`; // Toggle button const toggleButton = document.createElement('button'); toggleButton.className = 'menu-toggle'; toggleButton.textContent = '▼'; toggleButton.addEventListener('click', () => { if (menuContent.style.display === 'none') { menuContent.style.display = 'block'; toggleButton.textContent = '▲'; } else { menuContent.style.display = 'none'; toggleButton.textContent = '▼'; } }); menu.appendChild(toggleButton); // Menu content const menuContent = document.createElement('div'); menuContent.style.display = 'none'; // Shape buttons const shapes = { 'Circle': drawCircle, 'Square': (x, y, size, color, thickness) => drawPolygon(x, y, size, 4, color, thickness), 'Triangle': (x, y, size, color, thickness) => drawPolygon(x, y, size, 3, color, thickness), 'Pentagon': (x, y, size, color, thickness) => drawPolygon(x, y, size, 5, color, thickness), 'Hexagon': (x, y, size, color, thickness) => drawPolygon(x, y, size, 6, color, thickness), 'Octagon': (x, y, size, color, thickness) => drawPolygon(x, y, size, 8, color, thickness), 'Spiral': drawSpiral, }; for (const name in shapes) { const button = document.createElement('button'); button.textContent = name; button.addEventListener('click', () => { stopAllAnimations(); const color = colorInput.value; const thickness = parseInt(thicknessRange.value); const maxSize = parseFloat(sizeRange.value); recordAction({ shape: name, color, thickness, size: maxSize }); animateShape(shapes[name], 0.5, 0.5, maxSize, color, thickness); }); menuContent.appendChild(button); } // Add color and thickness controls const colorInput = document.createElement('input'); colorInput.type = 'color'; colorInput.value = '#000000'; menuContent.appendChild(document.createElement('label')).textContent = 'Color:'; menuContent.appendChild(colorInput); const thicknessRange = document.createElement('input'); thicknessRange.type = 'range'; thicknessRange.min = 1; thicknessRange.max = 50; // Expanded thickness range thicknessRange.value = 5; menuContent.appendChild(document.createElement('label')).textContent = 'Thickness:'; menuContent.appendChild(thicknessRange); const sizeRange = document.createElement('input'); sizeRange.type = 'range'; sizeRange.min = 0.1; sizeRange.max = 5; // Expanded max size sizeRange.value = 1; menuContent.appendChild(document.createElement('label')).textContent = 'Max Size:'; menuContent.appendChild(sizeRange); // Save/Load Presets const saveButton = document.createElement('button'); saveButton.textContent = 'Save Preset'; saveButton.addEventListener('click', () => { const presetName = prompt("Enter preset name:"); if (presetName) { localStorage.setItem(presetName, JSON.stringify(actions)); alert(`Preset ${presetName} saved!`); } }); menuContent.appendChild(saveButton); const loadButton = document.createElement('button'); loadButton.textContent = 'Load Preset'; loadButton.addEventListener('click', () => { const presetName = prompt("Enter preset name to load:"); const preset = localStorage.getItem(presetName); if (preset) { actions = JSON.parse(preset); alert(`Preset ${presetName} loaded!`); // Here you would need to re-execute the actions to draw them on the canvas. actions.forEach(action => { animateShape(shapes[action.shape], 0.5, 0.5, action.size, action.color, action.thickness); }); } else { alert("Preset not found!"); } }); menuContent.appendChild(loadButton); // Undo/Redo functionality const undoButton = document.createElement('button'); undoButton.textContent = 'Undo'; undoButton.addEventListener('click', () => { if (actions.length > 0) { const action = actions.pop(); redoActions.push(action); // Here you would need to draw the canvas state before the action was taken. // Implement your canvas state management logic here. } }); menuContent.appendChild(undoButton); const redoButton = document.createElement('button'); redoButton.textContent = 'Redo'; redoButton.addEventListener('click', () => { if (redoActions.length > 0) { const action = redoActions.pop(); actions.push(action); animateShape(shapes[action.shape], 0.5, 0.5, action.size, action.color, action.thickness); } }); menuContent.appendChild(redoButton); // Random Shape Generator const randomButton = document.createElement('button'); randomButton.textContent = 'Random Shape'; randomButton.addEventListener('click', () => { const shapeNames = Object.keys(shapes); const randomShape = shapeNames[Math.floor(Math.random() * shapeNames.length)]; const randomColor = `#${Math.floor(Math.random()*16777215).toString(16)}`; const randomThickness = Math.floor(Math.random() * (thicknessRange.max - thicknessRange.min + 1)) + thicknessRange.min; const randomSize = Math.random() * (sizeRange.max - sizeRange.min) + sizeRange.min; animateShape(shapes[randomShape], 0.5, 0.5, randomSize, randomColor, randomThickness); }); menuContent.appendChild(randomButton); // Clear/Stop Button const clearCanvasButton = document.createElement('button'); clearCanvasButton.textContent = 'Clear/Stop'; clearCanvasButton.addEventListener('click', () => { let data = ["drawcmd", 0, [0.5, 0.5, 0.5, 0.5, !0, -2000, "#FFFFFF", -1, !1]]; window.sockets.forEach(socket => { if (socket.readyState === WebSocket.OPEN) { socket.send(`42${JSON.stringify(data)}`); } }); stopAllAnimations(); actions = []; redoActions = []; animationRunning = false; }); menuContent.appendChild(clearCanvasButton); menu.appendChild(menuContent); // Animation functions let animationRunning = false; let animationId = null; function animateShape(shapeFunc, x, y, maxSize, color, thickness) { let currentSize = 0; const speed = 0.01; animationRunning = true; function drawFrame() { if (!animationRunning || currentSize > maxSize) { animationRunning = false; return; } shapeFunc(x, y, currentSize, color, thickness); currentSize += speed; animationId = requestAnimationFrame(drawFrame); } drawFrame(); } // Stop all animations function stopAllAnimations() { animationRunning = false; if (animationId) { cancelAnimationFrame(animationId); animationId = null; } } // WebSocket interception const originalSend = WebSocket.prototype.send; let sockets = []; WebSocket.prototype.send = function (...args) { if (sockets.indexOf(this) === -1) sockets.push(this); return originalSend.apply(this, args); }; // Make the menu draggable let isDragging = false; let offsetX, offsetY; menu.addEventListener('mousedown', e => { isDragging = true; offsetX = e.clientX - menu.getBoundingClientRect().left; offsetY = e.clientY - menu.getBoundingClientRect().top; }); document.addEventListener('mousemove', e => { if (isDragging) { menu.style.left = `${e.clientX - offsetX}px`; menu.style.top = `${e.clientY - offsetY}px`; } }); document.addEventListener('mouseup', () => isDragging = false); document.body.appendChild(menu); })();