FreeDraw Editor - Tutorial Completo

Guia de estrutura, classes, funções e bibliotecas

PHP 8.3+ HTML5 CSS3 JavaScript Fabric.js Bootstrap 5

📑 Índice

📁 1. ESTRUTURA DE ARQUIVOS

  • index.php # Página principal
  • .htaccess # Configurações Apache
  • assets/ # Recursos estáticos
    • css/
      • main.css
      • components.css
    • js/
      • app.js
      • tools.js
    • fonts/
    • icons/
  • temp/ # Arquivos temporários
    • exports/ # Arquivos exportados
    • projects/ # Projetos salvos
    • cache/
  • composer.json # Dependências PHP
💡 Importante: A pasta temp/ precisa ter permissão 755 para escrita.

📦 2. BIBLIOTECAS EXTERNAS (CDN)

Frontend (Carregadas via CDN):

<!-- Bootstrap 5.2.3 - Framework CSS/JS --> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js"></script> <!-- Font Awesome 6.4.0 - Ícones --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> <!-- Fabric.js 5.3.0 - Canvas Vetorial --> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script> <!-- jQuery 3.6.4 - Manipulação DOM --> <script src="https://code.jquery.com/jquery-3.6.4.min.js"></script>

Backend (Composer - PHP):

{ "require": { "php": ">=8.0", "intervention/image": "^3.0", # Manipulação de imagens "dompdf/dompdf": "^2.0", # Exportação PDF "phenx/php-svg-lib": "^0.5.0" # Manipulação SVG } }

🎨 3. CLASSES CSS PERSONALIZADAS

Classe Propósito Exemplo
.tool-btn Botões de ferramentas na sidebar <button class="tool-btn">
.color-chip Quadrados de cor na paleta <div class="color-chip">
.color-chip.selected Cor atualmente selecionada <div class="color-chip selected">
.sidebar-section Seções dentro da sidebar <div class="sidebar-section">
.btn-action Botões de ação principais <button class="btn-action">
.stroke-controls Container controles de borda <div class="stroke-controls">

Variáveis CSS (Custom Properties):

:root { --primary-color: #4a6fa5; /* Cor primária azul */ --secondary-color: #6c757d; /* Cor secundária cinza */ --dark-bg: #2c3e50; /* Fundo escuro */ --light-bg: #f8f9fa; /* Fundo claro */ --canvas-bg: #ffffff; /* Fundo do canvas */ --border-color: #dee2e6; /* Cor das bordas */ --shadow-sm: 0 2px 4px rgba(0,0,0,0.1); --shadow-md: 0 4px 8px rgba(0,0,0,0.15); --shadow-lg: 0 8px 16px rgba(0,0,0,0.2); }

⚙️ 4. ESTRUTURA JAVASCRIPT

Variáveis Globais Principais:

// Instância principal do canvas Fabric.js let canvas = null; // Estado da aplicação let activeTool = 'select'; // Ferramenta ativa: 'select', 'rectangle', etc. let selectedColor = '#000000'; // Cor selecionada let fillColor = '#FFFFFF'; // Cor de preenchimento atual let strokeColor = '#000000'; // Cor da borda atual let strokeWidth = 2; // Largura da borda em px let paintMode = 'fill'; // 'fill' ou 'stroke' let isDrawing = false; // Flag de desenho ativo let drawingObject = null; // Objeto sendo desenhado let history = []; // Histórico para undo/redo let historyIndex = -1; // Índice no histórico

Objeto de Configuração (APP):

const APP = { name: "FreeDraw Editor", version: "1.0.0", author: "Ferramentas da Web" }; // Paleta de 20 cores fixas const FIXED_COLORS = [ '#000000', '#333333', '#666666', '#999999', '#CCCCCC', '#FFFFFF', '#FF0000', '#FF6600', '#FFCC00', '#33CC33', '#0099CC', '#0066CC', '#6600CC', '#CC00CC', '#FF3366', '#FF9999', '#FFCCCC', '#CCFFCC', '#CCFFFF', '#CCCCFF' ];

Inicialização da Aplicação:

document.addEventListener('DOMContentLoaded', function() { initCanvas(); // 1. Inicializar canvas Fabric.js initColorPalette(); // 2. Configurar paleta de cores initToolEvents(); // 3. Eventos das ferramentas initCanvasEvents(); // 4. Eventos do canvas initKeyboardShortcuts();// 5. Atalhos de teclado loadSettings(); // 6. Carregar configurações showTips(); // 7. Mostrar dicas });

🔧 5. FUNÇÕES PRINCIPAIS

🎨 Funções de Cores

  • selectColor(color): Seleciona uma cor
  • applyColorToSelection(color): Aplica cor ao objeto selecionado
  • setPaintMode(mode): Define modo 'fill' ou 'stroke'
  • swapFillStroke(): Troca cores de preenchimento e borda
  • getContrastColor(hex): Calcula cor de contraste (preto/branco)

🖱️ Funções de Ferramentas

  • activateTool(toolName): Ativa uma ferramenta
  • createRectangle(x, y): Cria retângulo
  • createCircle(x, y): Cria círculo
  • createText(x, y): Cria texto editável
  • startDrawingLine(pointer): Inicia desenho de linha

📐 Funções de Canvas

  • initCanvas(): Inicializa canvas Fabric.js
  • resizeCanvasToContainer(): Ajusta tamanho do canvas
  • addBackgroundGrid(): Adiciona grid de fundo
  • toggleGrid(): Alterna visibilidade do grid
  • clearCanvas(): Limpa todo o canvas

Manipulação de Eventos:

// Evento de botão direito personalizado canvas.getElement().addEventListener('contextmenu', function(e) { e.preventDefault(); handleRightClick(e); }); // Eventos do mouse para desenho canvas.on('mouse:down', handleMouseDown); canvas.on('mouse:move', handleMouseMove); canvas.on('mouse:up', handleMouseUp); // Eventos de seleção canvas.on('selection:created', updatePropertiesPanel); canvas.on('selection:updated', updatePropertiesPanel); canvas.on('selection:cleared', updatePropertiesPanel);

Sistema de Histórico (Undo/Redo):

function saveToHistory() { // Remove estados futuros se houver undo if (historyIndex < history.length - 1) { history = history.slice(0, historyIndex + 1); } // Limita a 50 estados if (history.length >= 50) { history.shift(); } const state = JSON.stringify(canvas.toJSON()); history.push(state); historyIndex = history.length - 1; } function undo() { if (historyIndex > 0) { historyIndex--; const state = JSON.parse(history[historyIndex]); canvas.loadFromJSON(state); canvas.renderAll(); } }

🔗 6. API E BACKEND

Arquivo: api/save.php

<?php header('Content-Type: application/json'); header('Access-Control-Allow-Origin: *'); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $input = json_decode(file_get_contents('php://input'), true); $action = $input['action'] ?? ''; $filename = $input['filename'] ?? 'desenho_' . date('Ymd_His'); $data = $input['data'] ?? ''; // Sanitizar nome do arquivo $filename = preg_replace('/[^a-zA-Z0-9_-]/', '', $filename); $filepath = __DIR__ . '/../temp/projects/' . $filename . '.json'; // Criar diretório se não existir $projectDir = __DIR__ . '/../temp/projects'; if (!is_dir($projectDir)) { mkdir($projectDir, 0755, true); } if ($action === 'save') { $jsonData = json_encode([ 'metadata' => [ 'name' => $filename, 'created' => date('Y-m-d H:i:s'), 'version' => '1.0' ], 'content' => json_decode($data, true) ], JSON_PRETTY_UNICODE | JSON_PRETTY_PRINT); if (file_put_contents($filepath, $jsonData)) { echo json_encode([ 'success' => true, 'message' => 'Projeto salvo!', 'filepath' => 'temp/projects/' . $filename . '.json' ]); } } } ?>
📁 Permissões necessárias:
  • temp/: 755
  • temp/projects/: 755
  • temp/exports/: 755

⌨️ 7. ATALHOS DE TECLADO

Atalho Ação Descrição
V Ferramenta Seleção Volta para a ferramenta de seleção
R Ferramenta Retângulo Ativa desenho de retângulos
C Ferramenta Círculo Ativa desenho de círculos
T Ferramenta Texto Ativa adição de texto
P Ferramenta Caneta Ativa desenho livre
F Modo Preenchimento Alterna para aplicar preenchimento
B Modo Borda Alterna para aplicar bordas
X Trocar Cores Troca cores de preenchimento e borda
Ctrl + S Salvar Projeto Abre diálogo de salvamento
Ctrl + E Exportar SVG Exporta canvas como SVG
Ctrl + Z Desfazer Desfaz última ação
Ctrl + Y Refazer Refaz ação desfeita
Delete Remover Seleção Apaga objeto(s) selecionado(s)
Botão Direito Aplicar Borda Aplica cor atual na borda do objeto

🚀 8. COMO EXPANDIR O PROJETO

Adicionar Nova Ferramenta:

// 1. Adicionar botão no HTML <button class="tool-btn" data-tool="nova-ferramenta"> <i class="fas fa-novo-icone"></i> </button> // 2. Adicionar no switch da função activateTool() case 'nova-ferramenta': canvas.selection = false; canvas.defaultCursor = 'crosshair'; updateStatus('Nova ferramenta ativada'); break; // 3. Criar função de criação function startDrawingNovaFerramenta(pointer) { drawingObject = new fabric.[ObjetoFabric]({ // propriedades }); canvas.add(drawingObject); }

Adicionar Novo Efeito:

function aplicarEfeitoSombra() { const activeObject = canvas.getActiveObject(); if (activeObject) { activeObject.set({ shadow: new fabric.Shadow({ color: 'rgba(0,0,0,0.5)', blur: 10, offsetX: 5, offsetY: 5 }) }); canvas.renderAll(); } }

Adicionar Novo Formato de Exportação:

function exportPNG() { const dataURL = canvas.toDataURL({ format: 'png', quality: 1, multiplier: 2 }); const link = document.createElement('a'); link.href = dataURL; link.download = `desenho_${Date.now()}.png`; link.click(); }
💡 Dica para Expansão:

O projeto foi projetado para ser modular. Para adicionar qualquer funcionalidade:

  1. Adicione a UI no HTML (botões, controles)
  2. Adicione a lógica em JavaScript (funções)
  3. Conecte os eventos (addEventListener)
  4. Teste e refine
⚠️ Próximos Passos Sugeridos:
  • Implementar gradientes personalizados
  • Adicionar estilos de linha (tracejada, pontilhada)
  • Criar sistema de templates/shapes predefinidos
  • Implementar exportação para PDF usando dompdf
  • Adicionar suporte a importação de imagens
  • Criar sistema de plugins/módulos