Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>AI Drawing Board Pro</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #6C5CE7; | |
| --secondary: #00CEFF; | |
| --dark: #2D3436; | |
| --light: #F5F6FA; | |
| --accent: #FD79A8; | |
| --shadow: 0 4px 20px rgba(0, 0, 0, 0.1); | |
| --transition: all 0.3s ease; | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background-color: var(--light); | |
| color: var(--dark); | |
| overflow: hidden; | |
| height: 100vh; | |
| display: grid; | |
| grid-template-rows: auto 1fr auto; | |
| } | |
| header { | |
| background-color: white; | |
| padding: 1rem 2rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| box-shadow: var(--shadow); | |
| z-index: 10; | |
| } | |
| .logo { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| font-weight: 700; | |
| font-size: 1.3rem; | |
| color: var(--primary); | |
| } | |
| .logo i { | |
| font-size: 1.5rem; | |
| } | |
| .user-actions { | |
| display: flex; | |
| gap: 1rem; | |
| align-items: center; | |
| } | |
| .btn { | |
| padding: 0.6rem 1rem; | |
| border-radius: 6px; | |
| border: none; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .btn-primary { | |
| background-color: var(--primary); | |
| color: white; | |
| } | |
| .btn-primary:hover { | |
| background-color: #5344d4; | |
| transform: translateY(-2px); | |
| } | |
| .btn-outline { | |
| background-color: transparent; | |
| border: 2px solid var(--primary); | |
| color: var(--primary); | |
| } | |
| .btn-outline:hover { | |
| background-color: var(--primary); | |
| color: white; | |
| } | |
| .main-content { | |
| display: grid; | |
| grid-template-columns: 70px 1fr 250px; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| .toolbar { | |
| background-color: white; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| padding: 1.5rem 0.5rem; | |
| gap: 1.5rem; | |
| box-shadow: 4px 0 20px rgba(0, 0, 0, 0.05); | |
| z-index: 5; | |
| } | |
| .tool-btn { | |
| width: 45px; | |
| height: 45px; | |
| border-radius: 8px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| color: var(--dark); | |
| position: relative; | |
| } | |
| .tool-btn:hover { | |
| background-color: var(--light); | |
| color: var(--primary); | |
| } | |
| .tool-btn.active { | |
| background-color: var(--primary); | |
| color: white; | |
| } | |
| .tooltip { | |
| position: absolute; | |
| left: 55px; | |
| background-color: var(--dark); | |
| color: white; | |
| padding: 0.5rem 1rem; | |
| border-radius: 6px; | |
| font-size: 0.9rem; | |
| opacity: 0; | |
| pointer-events: none; | |
| transition: var(--transition); | |
| white-space: nowrap; | |
| } | |
| .tool-btn:hover .tooltip { | |
| opacity: 1; | |
| } | |
| .canvas-container { | |
| position: relative; | |
| overflow: hidden; | |
| background-image: linear-gradient(45deg, #e5e5e5 25%, transparent 25%), | |
| linear-gradient(-45deg, #e5e5e5 25%, transparent 25%), | |
| linear-gradient(45deg, transparent 75%, #e5e5e5 75%), | |
| linear-gradient(-45deg, transparent 75%, #e5e5e5 75%); | |
| background-size: 20px 20px; | |
| background-position: 0 0, 0 10px, 10px -10px, -10px 0px; | |
| } | |
| canvas { | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| cursor: crosshair; | |
| } | |
| .text-input-container { | |
| position: absolute; | |
| display: none; | |
| background: transparent; | |
| border: none; | |
| outline: none; | |
| font-family: inherit; | |
| font-size: 16px; | |
| padding: 0; | |
| margin: 0; | |
| color: var(--dark); | |
| } | |
| .ai-panel { | |
| background-color: white; | |
| padding: 1.5rem; | |
| display: flex; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| box-shadow: -4px 0 20px rgba(0, 0, 0, 0.05); | |
| z-index: 5; | |
| overflow-y: auto; | |
| } | |
| .panel-section { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.7rem; | |
| } | |
| .panel-title { | |
| font-weight: 600; | |
| color: var(--primary); | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .panel-title i { | |
| font-size: 0.9rem; | |
| } | |
| .color-picker { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.5rem; | |
| } | |
| .color-option { | |
| width: 25px; | |
| height: 25px; | |
| border-radius: 50%; | |
| cursor: pointer; | |
| border: 2px solid #eee; | |
| transition: var(--transition); | |
| } | |
| .color-option:hover { | |
| transform: scale(1.1); | |
| } | |
| .brush-size { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 0.5rem; | |
| } | |
| .slider { | |
| -webkit-appearance: none; | |
| width: 100%; | |
| height: 6px; | |
| border-radius: 3px; | |
| background: #ddd; | |
| outline: none; | |
| } | |
| .slider::-webkit-slider-thumb { | |
| -webkit-appearance: none; | |
| appearance: none; | |
| width: 16px; | |
| height: 16px; | |
| border-radius: 50%; | |
| background: var(--primary); | |
| cursor: pointer; | |
| } | |
| .font-selector { | |
| width: 100%; | |
| padding: 0.5rem; | |
| border-radius: 6px; | |
| border: 1px solid #ddd; | |
| font-size: 0.9rem; | |
| } | |
| .font-size-selector { | |
| display: flex; | |
| gap: 0.5rem; | |
| align-items: center; | |
| } | |
| .font-size-selector input { | |
| width: 60px; | |
| padding: 0.3rem; | |
| border-radius: 4px; | |
| border: 1px solid #ddd; | |
| } | |
| .layer { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| padding: 0.5rem; | |
| border-radius: 6px; | |
| cursor: pointer; | |
| } | |
| .layer:hover { | |
| background-color: var(--light); | |
| } | |
| .layer.active { | |
| background-color: var(--light); | |
| border-left: 3px solid var(--primary); | |
| } | |
| .layer-controls { | |
| display: flex; | |
| gap: 0.5rem; | |
| opacity: 0; | |
| transition: var(--transition); | |
| } | |
| .layer:hover .layer-controls { | |
| opacity: 1; | |
| } | |
| .ai-suggestion { | |
| background-color: var(--light); | |
| border-radius: 8px; | |
| padding: 1rem; | |
| margin-bottom: 1rem; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .ai-suggestion:hover { | |
| background-color: #e2e2ff; | |
| } | |
| .ai-suggestion h4 { | |
| color: var(--primary); | |
| margin-bottom: 0.5rem; | |
| font-size: 0.9rem; | |
| } | |
| .ai-suggestion p { | |
| font-size: 0.8rem; | |
| color: #666; | |
| } | |
| footer { | |
| background-color: white; | |
| padding: 0.8rem; | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| font-size: 0.9rem; | |
| box-shadow: 0 -4px 10px rgba(0, 0, 0, 0.05); | |
| } | |
| .zoom-controls { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.5rem; | |
| } | |
| .zoom-btn { | |
| width: 30px; | |
| height: 30px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| background-color: var(--light); | |
| cursor: pointer; | |
| transition: var(--transition); | |
| } | |
| .zoom-btn:hover { | |
| background-color: #ddd; | |
| } | |
| .status-info { | |
| display: flex; | |
| gap: 1rem; | |
| } | |
| .status-item { | |
| display: flex; | |
| align-items: center; | |
| gap: 0.3rem; | |
| color: #666; | |
| font-size: 0.8rem; | |
| } | |
| .ai-assistant-toggle { | |
| position: fixed; | |
| bottom: 20px; | |
| right: 20px; | |
| background-color: var(--primary); | |
| color: white; | |
| width: 60px; | |
| height: 60px; | |
| border-radius: 50%; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| cursor: pointer; | |
| box-shadow: var(--shadow); | |
| transition: var(--transition); | |
| z-index: 100; | |
| } | |
| .ai-assistant-toggle:hover { | |
| transform: scale(1.1); | |
| background-color: #5344d4; | |
| } | |
| .context-menu { | |
| position: absolute; | |
| background-color: white; | |
| border-radius: 8px; | |
| box-shadow: var(--shadow); | |
| z-index: 1000; | |
| display: none; | |
| flex-direction: column; | |
| min-width: 200px; | |
| overflow: hidden; | |
| } | |
| .menu-item { | |
| padding: 0.8rem 1rem; | |
| cursor: pointer; | |
| display: flex; | |
| align-items: center; | |
| gap: 0.7rem; | |
| transition: var(--transition); | |
| } | |
| .menu-item:hover { | |
| background-color: var(--light); | |
| } | |
| .ai-generation-popup { | |
| position: fixed; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background-color: white; | |
| border-radius: 12px; | |
| box-shadow: var(--shadow); | |
| padding: 2rem; | |
| z-index: 1000; | |
| width: 90%; | |
| max-width: 600px; | |
| display: none; | |
| flex-direction: column; | |
| gap: 1.5rem; | |
| } | |
| .ai-generation-header { | |
| display: flex; | |
| justify-content: space-between; | |
| align-items: center; | |
| } | |
| .ai-generation-body { | |
| display: grid; | |
| grid-template-columns: repeat(3, 1fr); | |
| gap: 1rem; | |
| } | |
| .ai-option { | |
| border-radius: 8px; | |
| overflow: hidden; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| border: 2px solid #eee; | |
| } | |
| .ai-option:hover { | |
| border-color: var(--primary); | |
| transform: translateY(-5px); | |
| } | |
| .ai-option-image { | |
| height: 120px; | |
| background-color: var(--light); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .ai-option-label { | |
| padding: 0.8rem; | |
| background-color: white; | |
| font-size: 0.9rem; | |
| text-align: center; | |
| font-weight: 500; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <header> | |
| <div class="logo"> | |
| <i class="fas fa-magic"></i> | |
| <span>AI Drawing Board Pro</span> | |
| </div> | |
| <div class="user-actions"> | |
| <button class="btn btn-outline"> | |
| <i class="fas fa-cloud-upload-alt"></i> | |
| Save | |
| </button> | |
| <button class="btn btn-primary"> | |
| <i class="fas fa-share-alt"></i> | |
| Export | |
| </button> | |
| </div> | |
| </header> | |
| <div class="main-content"> | |
| <div class="toolbar"> | |
| <div class="tool-btn" id="brushToolBtn"> | |
| <i class="fas fa-pen"></i> | |
| <div class="tooltip">Brush (B)</div> | |
| </div> | |
| <div class="tool-btn" id="eraserToolBtn"> | |
| <i class="fas fa-eraser"></i> | |
| <div class="tooltip">Eraser (E)</div> | |
| </div> | |
| <div class="tool-btn" id="lineToolBtn"> | |
| <i class="fas fa-slash"></i> | |
| <div class="tooltip">Line (L)</div> | |
| </div> | |
| <div class="tool-btn" id="rectangleToolBtn"> | |
| <i class="fas fa-square"></i> | |
| <div class="tooltip">Rectangle (R)</div> | |
| </div> | |
| <div class="tool-btn" id="circleToolBtn"> | |
| <i class="fas fa-circle"></i> | |
| <div class="tooltip">Circle (C)</div> | |
| </div> | |
| <div class="tool-btn" id="textToolBtn"> | |
| <i class="fas fa-font"></i> | |
| <div class="tooltip">Text (T)</div> | |
| </div> | |
| <div class="tool-btn"> | |
| <i class="fas fa-cut"></i> | |
| <div class="tooltip">Crop (X)</div> | |
| </div> | |
| <div class="tool-btn"> | |
| <i class="fas fa-magic"></i> | |
| <div class="tooltip">AI Enhance (A)</div> | |
| </div> | |
| <div class="tool-btn"> | |
| <i class="fas fa-object-group"></i> | |
| <div class="tooltip">Shapes (S)</div> | |
| </div> | |
| <div class="tool-btn"> | |
| <i class="fas fa-fill-drip"></i> | |
| <div class="tooltip">Fill (G)</div> | |
| </div> | |
| <div class="tool-btn"> | |
| <i class="fas fa-vector-square"></i> | |
| <div class="tooltip">Select (V)</div> | |
| </div> | |
| <div class="tool-btn"> | |
| <i class="fas fa-eye-dropper"></i> | |
| <div class="tooltip">Color Picker (I)</div> | |
| </div> | |
| </div> | |
| <div class="canvas-container"> | |
| <canvas id="main-canvas"></canvas> | |
| <div class="text-input-container" id="textInputContainer" contenteditable="true"></div> | |
| <div class="ai-generation-popup" id="aiGenerationPopup"> | |
| <div class="ai-generation-header"> | |
| <h3>AI Generation Options</h3> | |
| <i class="fas fa-times" id="closeAiPopup"></i> | |
| </div> | |
| <div class="ai-generation-body"> | |
| <div class="ai-option"> | |
| <div class="ai-option-image"></div> | |
| <div class="ai-option-label">Background Removal</div> | |
| </div> | |
| <div class="ai-option"> | |
| <div class="ai-option-image"></div> | |
| <div class="ai-option-label">Colorize Sketch</div> | |
| </div> | |
| <div class="ai-option"> | |
| <div class="ai-option-image"></div> | |
| <div class="ai-option-label">Upscale Image</div> | |
| </div> | |
| <div class="ai-option"> | |
| <div class="ai-option-image"></div> | |
| <div class="ai-option-label">Style Transfer</div> | |
| </div> | |
| <div class="ai-option"> | |
| <div class="ai-option-image"></div> | |
| <div class="ai-option-label">Smart Fill</div> | |
| </div> | |
| <div class="ai-option"> | |
| <div class="ai-option-image"></div> | |
| <div class="ai-option-label">Generate Pattern</div> | |
| </div> | |
| </div> | |
| <button class="btn btn-primary"> | |
| <i class="fas fa-magic"></i> | |
| Generate Variations | |
| </button> | |
| </div> | |
| </div> | |
| <div class="ai-panel"> | |
| <div class="panel-section"> | |
| <h3 class="panel-title"> | |
| <i class="fas fa-palette"></i> | |
| Colors | |
| </h3> | |
| <div class="color-picker" id="colorPicker"> | |
| <!-- Colors will be added by JavaScript --> | |
| </div> | |
| </div> | |
| <div class="panel-section"> | |
| <h3 class="panel-title"> | |
| <i class="fas fa-paint-bbrush"></i> | |
| Brush Size | |
| </h3> | |
| <div class="brush-size"> | |
| <input type="range" min="1" max="50" value="5" class="slider" id="brushSize"> | |
| <div style="text-align: center; font-size: 0.8rem;">5px</div> | |
| </div> | |
| </div> | |
| <div class="panel-section"> | |
| <h3 class="panel-title"> | |
| <i class="fas fa-font"></i> | |
| Text Settings | |
| </h3> | |
| <select class="font-selector" id="fontFamily"> | |
| <option value="Arial">Arial</option> | |
| <option value="Verdana">Verdana</option> | |
| <option value="Georgia">Georgia</option> | |
| <option value="Times New Roman">Times New Roman</option> | |
| <option value="Courier New">Courier New</option> | |
| <option value="Comic Sans MS">Comic Sans MS</option> | |
| <option value="Impact">Impact</option> | |
| </select> | |
| <div class="font-size-selector"> | |
| <input type="number" id="fontSize" value="16" min="8" max="72"> | |
| <span>px</span> | |
| </div> | |
| </div> | |
| <div class="panel-section"> | |
| <h3 class="panel-title"> | |
| <i class="fas fa-layer-group"></i> | |
| Layers | |
| </h3> | |
| <div class="layers-list" id="layersList"> | |
| <div class="layer active"> | |
| <span>Layer 1</span> | |
| <div class="layer-controls"> | |
| <i class="fas fa-eye"></i> | |
| <i class="fas fa-trash-alt"></i> | |
| </div> | |
| </div> | |
| <div class="layer"> | |
| <span>Layer 2</span> | |
| <div class="layer-controls"> | |
| <i class="fas fa-eye"></i> | |
| <i class="fas fa-trash-alt"></i> | |
| </div> | |
| </div> | |
| <div class="layer"> | |
| <span>Sketch</span> | |
| <div class="layer-controls"> | |
| <i class="fas fa-eye"></i> | |
| <i class="fas fa-trash-alt"></i> | |
| </div> | |
| </div> | |
| </div> | |
| <button class="btn btn-outline" style="margin-top: 0.5rem;">Add Layer</button> | |
| </div> | |
| <div class="panel-section"> | |
| <h3 class="panel-title"> | |
| <i class="fas fa-robot"></i> | |
| AI Suggestions | |
| </h3> | |
| <div class="ai-suggestions"> | |
| <div class="ai-suggestion"> | |
| <h4>Color Scheme</h4> | |
| <p>Try this complementary color palette for your design</p> | |
| </div> | |
| <div class="ai-suggestion"> | |
| <h4>Composition</h4> | |
| <p>Consider adding more negative space to improve balance</p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <footer> | |
| <div class="zoom-controls"> | |
| <div class="zoom-btn" id="zoomOut"> | |
| <i class="fas fa-search-minus"></i> | |
| </div> | |
| <span>100%</span> | |
| <div class="zoom-btn" id="zoomIn"> | |
| <i class="fas fa-search-plus"></i> | |
| </div> | |
| </div> | |
| <div class="status-info"> | |
| <div class="status-item"> | |
| <i class="fas fa-expand"></i> | |
| <span>1920x1080px</span> | |
| </div> | |
| <div class="status-item"> | |
| <i class="fas fa-tint"></i> | |
| <span>#6C5CE7</span> | |
| </div> | |
| <div class="status-item"> | |
| <i class="fas fa-clock"></i> | |
| <span>Auto-saved</span> | |
| </div> | |
| </div> | |
| </footer> | |
| <div class="ai-assistant-toggle" id="aiAssistant"> | |
| <i class="fas fa-robot fa-lg"></i> | |
| </div> | |
| <div class="context-menu" id="contextMenu"> | |
| <div class="menu-item"> | |
| <i class="fas fa-plus-circle"></i> | |
| <span>New Layer</span> | |
| </div> | |
| <div class="menu-item"> | |
| <i class="fas fa-copy"></i> | |
| <span>Duplicate</span> | |
| </div> | |
| <div class="menu-item"> | |
| <i class="fas fa-trash-alt"></i> | |
| <span>Delete</span> | |
| </div> | |
| <div class="menu-item"> | |
| <i class="fas fa-magic"></i> | |
| <span>AI Enhance</span> | |
| </div> | |
| <div class="menu-item"> | |
| <i class="fas fa-layer-group"></i> | |
| <span>Merge Down</span> | |
| </div> | |
| </div> | |
| <script> | |
| // Initialize canvas | |
| const canvas = document.getElementById('main-canvas'); | |
| const ctx = canvas.getContext('2d'); | |
| const textInputContainer = document.getElementById('textInputContainer'); | |
| // Set canvas size | |
| function resizeCanvas() { | |
| const container = document.querySelector('.canvas-container'); | |
| canvas.width = container.clientWidth; | |
| canvas.height = container.clientHeight; | |
| // Redraw content here in a real app | |
| ctx.fillStyle = 'white'; | |
| ctx.fillRect(0, 0, canvas.width, canvas.height); | |
| } | |
| window.addEventListener('resize', resizeCanvas); | |
| resizeCanvas(); | |
| // Drawing functionality | |
| let isDrawing = false; | |
| let lastX = 0; | |
| let lastY = 0; | |
| let brushSize = 5; | |
| let currentColor = '#6C5CE7'; | |
| let currentTool = 'brush'; // Default to brush tool | |
| let currentFont = 'Arial'; | |
| let currentFontSize = 16; | |
| // Variables for shape drawing | |
| let startX, startY; | |
| let isDrawingShape = false; | |
| let tempCanvas = document.createElement('canvas'); | |
| let tempCtx = tempCanvas.getContext('2d'); | |
| tempCanvas.width = canvas.width; | |
| tempCanvas.height = canvas.height; | |
| // Text tool functionality | |
| canvas.addEventListener('click', (e) => { | |
| if (currentTool === 'text') { | |
| const rect = canvas.getBoundingClientRect(); | |
| const x = e.clientX - rect.left; | |
| const y = e.clientY - rect.top; | |
| textInputContainer.style.display = 'block'; | |
| textInputContainer.style.left = `${x}px`; | |
| textInputContainer.style.top = `${y}px`; | |
| textInputContainer.style.color = currentColor; | |
| textInputContainer.style.fontFamily = currentFont; | |
| textInputContainer.style.fontSize = `${currentFontSize}px`; | |
| textInputContainer.focus(); | |
| } | |
| }); | |
| textInputContainer.addEventListener('keydown', (e) => { | |
| if (e.key === 'Enter') { | |
| finalizeText(); | |
| } else if (e.key === 'Escape') { | |
| cancelTextInput(); | |
| } | |
| }); | |
| textInputContainer.addEventListener('blur', () => { | |
| finalizeText(); | |
| }); | |
| function finalizeText() { | |
| const text = textInputContainer.textContent.trim(); | |
| if (text) { | |
| const x = parseInt(textInputContainer.style.left); | |
| const y = parseInt(textInputContainer.style.top) + parseInt(currentFontSize); | |
| ctx.fillStyle = textInputContainer.style.color; | |
| ctx.font = `${currentFontSize}px ${currentFont}`; | |
| ctx.fillText(text, x, y); | |
| } | |
| cancelTextInput(); | |
| } | |
| function cancelTextInput() { | |
| textInputContainer.style.display = 'none'; | |
| textInputContainer.textContent = ''; | |
| } | |
| // Drawing event handlers | |
| canvas.addEventListener('mousedown', startDrawing); | |
| canvas.addEventListener('mousemove', draw); | |
| canvas.addEventListener('mouseup', stopDrawing); | |
| canvas.addEventListener('mouseout', stopDrawing); | |
| function startDrawing(e) { | |
| if (currentTool === 'text') return; | |
| const rect = canvas.getBoundingClientRect(); | |
| startX = e.clientX - rect.left; | |
| startY = e.clientY - rect.top; | |
| isDrawing = true; | |
| [lastX, lastY] = [startX, startY]; | |
| // For shapes, we'll use a temporary canvas to show the shape while drawing | |
| if (['rectangle', 'circle', 'line'].includes(currentTool)) { | |
| isDrawingShape = true; | |
| tempCanvas.width = canvas.width; | |
| tempCanvas.height = canvas.height; | |
| tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height); | |
| } | |
| } | |
| function draw(e) { | |
| if (currentTool === 'text' || !isDrawing) return; | |
| const rect = canvas.getBoundingClientRect(); | |
| const currentX = e.clientX - rect.left; | |
| const currentY = e.clientY - rect.top; | |
| if (['rectangle', 'circle', 'line'].includes(currentTool)) { | |
| // Clear temporary canvas | |
| tempCtx.clearRect(0, 0, tempCanvas.width, tempCanvas.height); | |
| // Draw current shape on temporary canvas | |
| tempCtx.strokeStyle = currentColor; | |
| tempCtx.lineWidth = brushSize; | |
| tempCtx.fillStyle = currentColor; | |
| switch (currentTool) { | |
| case 'rectangle': | |
| tempCtx.strokeRect(startX, startY, currentX - startX, currentY - startY); | |
| break; | |
| case 'circle': | |
| const radius = Math.sqrt(Math.pow(currentX - startX, 2) + Math.pow(currentY - startY, 2)); | |
| tempCtx.beginPath(); | |
| tempCtx.arc(startX, startY, radius, 0, Math.PI * 2); | |
| tempCtx.stroke(); | |
| break; | |
| case 'line': | |
| tempCtx.beginPath(); | |
| tempCtx.moveTo(startX, startY); | |
| tempCtx.lineTo(currentX, currentY); | |
| tempCtx.stroke(); | |
| break; | |
| } | |
| // Draw the temporary canvas onto the main canvas | |
| ctx.clearRect(0, 0, canvas.width, canvas.height); | |
| ctx.drawImage(tempCanvas, 0, 0); | |
| } else { | |
| // Regular brush/eraser drawing | |
| ctx.strokeStyle = currentTool === 'eraser' ? 'white' : currentColor; | |
| ctx.lineJoin = 'round'; | |
| ctx.lineCap = 'round'; | |
| ctx.lineWidth = brushSize; | |
| ctx.beginPath(); | |
| ctx.moveTo(lastX, lastY); | |
| ctx.lineTo(currentX, currentY); | |
| ctx.stroke(); | |
| [lastX, lastY] = [currentX, currentY]; | |
| } | |
| } | |
| function stopDrawing() { | |
| if (isDrawingShape && ['rectangle', 'circle', 'line'].includes(currentTool)) { | |
| // Finalize the shape | |
| switch (currentTool) { | |
| case 'rectangle': | |
| ctx.strokeStyle = currentColor; | |
| ctx.lineWidth = brushSize; | |
| ctx.strokeRect(startX, startY, lastX - startX, lastY - startY); | |
| break; | |
| case 'circle': | |
| const radius = Math.sqrt(Math.pow(lastX - startX, 2) + Math.pow(lastY - startY, 2)); | |
| ctx.strokeStyle = currentColor; | |
| ctx.lineWidth = brushSize; | |
| ctx.beginPath(); | |
| ctx.arc(startX, startY, radius, 0, Math.PI * 2); | |
| ctx.stroke(); | |
| break; | |
| case 'line': | |
| ctx.strokeStyle = currentColor; | |
| ctx.lineWidth = brushSize; | |
| ctx.beginPath(); | |
| ctx.moveTo(startX, startY); | |
| ctx.lineTo(lastX, lastY); | |
| ctx.stroke(); | |
| break; | |
| } | |
| } | |
| isDrawing = false; | |
| isDrawingShape = false; | |
| } | |
| // Tool selection | |
| const toolButtons = document.querySelectorAll('.tool-btn'); | |
| const brushToolBtn = document.getElementById('brushToolBtn'); | |
| const eraserToolBtn = document.getElementById('eraserToolBtn'); | |
| const lineToolBtn = document.getElementById('lineToolBtn'); | |
| const rectangleToolBtn = document.getElementById('rectangleToolBtn'); | |
| const circleToolBtn = document.getElementById('circleToolBtn'); | |
| const textToolBtn = document.getElementById('textToolBtn'); | |
| function activateTool(button, tool) { | |
| toolButtons.forEach(btn => btn.classList.remove('active')); | |
| button.classList.add('active'); | |
| currentTool = tool; | |
| cancelTextInput(); | |
| // Set appropriate cursor | |
| switch (tool) { | |
| case 'brush': | |
| canvas.style.cursor = 'crosshair'; | |
| break; | |
| case 'eraser': | |
| canvas.style.cursor = 'url("data:image/svg+xml;utf8,<svg xmlns=\'http://www.w3.org/2000/svg\' width=\'24\' height=\'24\' viewBox=\'0 0 24 24\' fill=\'none\' stroke=\'black\' stroke-width=\'2\' stroke-linecap=\'round\' stroke-linejoin=\'round\'><path d=\'M3 6h18\'/><path d=\'M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2\'/><line x1=\'10\' y1=\'11\' x2=\'10\' y2=\'17\'/><line x1=\'14\' y1=\'11\' x2=\'14\' y2=\'17\'/></svg>"), auto'; | |
| break; | |
| case 'line': | |
| case 'rectangle': | |
| case 'circle': | |
| canvas.style.cursor = 'crosshair'; | |
| break; | |
| case 'text': | |
| canvas.style.cursor = 'text'; | |
| break; | |
| default: | |
| canvas.style.cursor = 'default'; | |
| } | |
| } | |
| brushToolBtn.addEventListener('click', () => activateTool(brushToolBtn, 'brush')); | |
| eraserToolBtn.addEventListener('click', () => activateTool(eraserToolBtn, 'eraser')); | |
| lineToolBtn.addEventListener('click', () => activateTool(lineToolBtn, 'line')); | |
| rectangleToolBtn.addEventListener('click', () => activateTool(rectangleToolBtn, 'rectangle')); | |
| circleToolBtn.addEventListener('click', () => activateTool(circleToolBtn, 'circle')); | |
| textToolBtn.addEventListener('click', () => activateTool(textToolBtn, 'text')); | |
| // Start with brush tool active | |
| activateTool(brushToolBtn, 'brush'); | |
| // Color picker | |
| const colors = [ | |
| '#6C5CE7', '#00CEFF', '#00B894', '#FD79A8', | |
| '#FDCB6E', '#E17055', '#BDC581', '#74B9FF', | |
| '#2D3436', '#F5F6FA', '#FFFFFF', '#000000' | |
| ]; | |
| const colorPicker = document.getElementById('colorPicker'); | |
| colors.forEach(color => { | |
| const colorOption = document.createElement('div'); | |
| colorOption.className = 'color-option'; | |
| colorOption.style.backgroundColor = color; | |
| colorOption.addEventListener('click', () => { | |
| currentColor = color; | |
| document.querySelector('.status-item:nth-child(2) span').textContent = color; | |
| }); | |
| colorPicker.appendChild(colorOption); | |
| }); | |
| // Brush size | |
| const brushSizeSlider = document.getElementById('brushSize'); | |
| brushSizeSlider.addEventListener('input', () => { | |
| brushSize = brushSizeSlider.value; | |
| document.querySelector('.brush-size div').textContent = `${brushSize}px`; | |
| }); | |
| // Font settings | |
| const fontFamilySelect = document.getElementById('fontFamily'); | |
| fontFamilySelect.addEventListener('change', () => { | |
| currentFont = fontFamilySelect.value; | |
| }); | |
| const fontSizeInput = document.getElementById('fontSize'); | |
| fontSizeInput.addEventListener('change', () => { | |
| currentFontSize = parseInt(fontSizeInput.value); | |
| if (currentFontSize < 8) currentFontSize = 8; | |
| if (currentFontSize > 72) currentFontSize = 72; | |
| fontSizeInput.value = currentFontSize; | |
| }); | |
| // Zoom controls | |
| document.getElementById('zoomIn').addEventListener('click', () => { | |
| const zoomText = document.querySelector('.zoom-controls span'); | |
| let zoom = parseInt(zoomText.textContent); | |
| if (zoom < 500) { | |
| zoom += 10; | |
| zoomText.textContent = `${zoom}%`; | |
| } | |
| }); | |
| document.getElementById('zoomOut').addEventListener('click', () => { | |
| const zoomText = document.querySelector('.zoom-controls span'); | |
| let zoom = parseInt(zoomText.textContent); | |
| if (zoom > 10) { | |
| zoom -= 10; | |
| zoomText.textContent = `${zoom}%`; | |
| } | |
| }); | |
| // AI Assistant | |
| document.getElementById('aiAssistant').addEventListener('click', () => { | |
| const popup = document.getElementById('aiGenerationPopup'); | |
| popup.style.display = 'flex'; | |
| }); | |
| document.getElementById('closeAiPopup').addEventListener('click', () => { | |
| document.getElementById('aiGenerationPopup').style.display = 'none'; | |
| }); | |
| // Context menu | |
| canvas.addEventListener('contextmenu', (e) => { | |
| e.preventDefault(); | |
| if (currentTool === 'text' && textInputContainer.style.display === 'block') return; | |
| const menu = document.getElementById('contextMenu'); | |
| menu.style.display = 'flex'; | |
| // Position the menu where the right click occurred | |
| menu.style.left = `${e.pageX}px`; | |
| menu.style.top = `${e.pageY}px`; | |
| // Close menu when clicking elsewhere | |
| function closeMenu() { | |
| menu.style.display = 'none'; | |
| document.removeEventListener('click', closeMenu); | |
| } | |
| setTimeout(() => { | |
| document.addEventListener('click', closeMenu); | |
| }, 100); | |
| }); | |
| // Layer selection | |
| const layers = document.querySelectorAll('.layer'); | |
| layers.forEach(layer => { | |
| layer.addEventListener('click', () => { | |
| layers.forEach(l => l.classList.remove('active')); | |
| layer.classList.add('active'); | |
| }); | |
| }); | |
| </script> | |
| <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: absolute; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">This website has been generated by <a href="https://enzostvs-deepsite.hf.space" style="color: #fff;" target="_blank" >DeepSite</a> <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;"></p></body> | |
| </html> |