FreeDraw Editor - Tutorial Completo
Guia de estrutura, classes, funções e bibliotecas
PHP 8.3+
HTML5
CSS3
JavaScript
Fabric.js
Bootstrap 5
📁 1. ESTRUTURA DE ARQUIVOS
index.php # Página principal
.htaccess # Configurações Apache
assets/ # Recursos estáticos
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:
Adicione a UI no HTML (botões, controles)
Adicione a lógica em JavaScript (funções)
Conecte os eventos (addEventListener)
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
FreeDraw Editor v1.0.0 - Tutorial Completo
Estrutura modular pronta para expansão. Qualquer dúvida, consulte este documento.
Última atualização: