UNPKG

@cognima/banners

Version:

Biblioteca avançada para geração de banners dinâmicos para diversas plataformas e aplicações

357 lines (312 loc) 11.3 kB
"use strict"; /** * Módulo de Efeitos Visuais para @cognima/banners * * Este módulo contém funções para aplicar efeitos visuais avançados aos banners, * como gradientes, sombras, brilhos, padrões e outros efeitos decorativos. * * @author Cognima Team (melhorado) * @version 2.0.0 */ const { createLinearGradient, hexToRgba, roundRect } = require("../utils"); /** * Aplica um efeito de vidro fosco (glassmorphism) * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {number} radius - Raio dos cantos * @param {number} opacity - Opacidade (0-1) * @param {string} color - Cor base (hexadecimal) */ function applyGlassmorphism(ctx, x, y, width, height, radius = 10, opacity = 0.2, color = "#FFFFFF") { // Fundo semi-transparente ctx.fillStyle = hexToRgba(color, opacity); roundRect(ctx, x, y, width, height, radius, true, false); // Borda sutil ctx.strokeStyle = hexToRgba(color, opacity + 0.1); ctx.lineWidth = 1; roundRect(ctx, x, y, width, height, radius, false, true); // Brilho superior (efeito de vidro) const gradient = createLinearGradient( ctx, x, y, x, y + height * 0.5, hexToRgba(color, opacity + 0.1), hexToRgba(color, 0), "vertical" ); ctx.fillStyle = gradient; roundRect(ctx, x, y, width, height * 0.5, { tl: radius, tr: radius, br: 0, bl: 0 }, true, false); } /** * Aplica um efeito de neomorfismo * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {number} radius - Raio dos cantos * @param {string} baseColor - Cor base (hexadecimal) * @param {boolean} pressed - Se o elemento está pressionado */ function applyNeomorphism(ctx, x, y, width, height, radius = 10, baseColor = "#E0E0E0", pressed = false) { // Salva o estado atual ctx.save(); // Desenha o fundo base ctx.fillStyle = baseColor; roundRect(ctx, x, y, width, height, radius, true, false); if (pressed) { // Efeito pressionado (sombra interna) ctx.shadowColor = "rgba(0, 0, 0, 0.2)"; ctx.shadowBlur = 15; ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; roundRect(ctx, x + 2, y + 2, width - 4, height - 4, radius - 2, false, true); ctx.shadowColor = "rgba(255, 255, 255, 0.7)"; ctx.shadowOffsetX = -5; ctx.shadowOffsetY = -5; roundRect(ctx, x + 2, y + 2, width - 4, height - 4, radius - 2, false, true); } else { // Efeito normal (sombra externa) ctx.shadowColor = "rgba(0, 0, 0, 0.2)"; ctx.shadowBlur = 15; ctx.shadowOffsetX = 5; ctx.shadowOffsetY = 5; roundRect(ctx, x, y, width, height, radius, false, true); ctx.shadowColor = "rgba(255, 255, 255, 0.7)"; ctx.shadowOffsetX = -5; ctx.shadowOffsetY = -5; roundRect(ctx, x, y, width, height, radius, false, true); } // Restaura o estado ctx.restore(); } /** * Aplica um efeito de gradiente com várias cores * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {Array} colors - Array de cores (hexadecimal) * @param {string} direction - Direção do gradiente ('horizontal', 'vertical', 'diagonal', 'radial') */ function applyMultiColorGradient(ctx, x, y, width, height, colors, direction = 'horizontal') { if (!colors || colors.length < 2) { throw new Error("São necessárias pelo menos duas cores para criar um gradiente."); } let gradient; if (direction === 'radial') { // Gradiente radial const centerX = x + width / 2; const centerY = y + height / 2; const radius = Math.max(width, height) / 2; gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius); } else { // Gradiente linear switch (direction) { case 'horizontal': gradient = ctx.createLinearGradient(x, y, x + width, y); break; case 'vertical': gradient = ctx.createLinearGradient(x, y, x, y + height); break; case 'diagonal': default: gradient = ctx.createLinearGradient(x, y, x + width, y + height); break; } } // Adiciona as cores ao gradiente const step = 1 / (colors.length - 1); colors.forEach((color, index) => { gradient.addColorStop(index * step, color); }); return gradient; } /** * Aplica um efeito de padrão de pontos * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {number} spacing - Espaçamento entre os pontos * @param {number} radius - Raio dos pontos * @param {string} color - Cor dos pontos (hexadecimal) * @param {number} opacity - Opacidade dos pontos (0-1) */ function applyDotPattern(ctx, x, y, width, height, spacing = 20, radius = 2, color = "#000000", opacity = 0.2) { // Salva o estado atual ctx.save(); // Define a cor e opacidade ctx.fillStyle = hexToRgba(color, opacity); // Desenha os pontos for (let posX = x; posX < x + width; posX += spacing) { for (let posY = y; posY < y + height; posY += spacing) { ctx.beginPath(); ctx.arc(posX, posY, radius, 0, Math.PI * 2); ctx.fill(); } } // Restaura o estado ctx.restore(); } /** * Aplica um efeito de padrão de linhas * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {number} spacing - Espaçamento entre as linhas * @param {number} lineWidth - Largura das linhas * @param {string} color - Cor das linhas (hexadecimal) * @param {number} opacity - Opacidade das linhas (0-1) * @param {string} direction - Direção das linhas ('horizontal', 'vertical', 'diagonal') */ function applyLinePattern(ctx, x, y, width, height, spacing = 20, lineWidth = 1, color = "#000000", opacity = 0.2, direction = 'horizontal') { // Salva o estado atual ctx.save(); // Define a cor, opacidade e largura da linha ctx.strokeStyle = hexToRgba(color, opacity); ctx.lineWidth = lineWidth; // Desenha as linhas switch (direction) { case 'vertical': for (let posX = x; posX < x + width; posX += spacing) { ctx.beginPath(); ctx.moveTo(posX, y); ctx.lineTo(posX, y + height); ctx.stroke(); } break; case 'diagonal': const diagonal = Math.sqrt(width * width + height * height); const steps = diagonal / spacing; const stepX = width / steps; const stepY = height / steps; for (let i = -steps; i <= steps * 2; i++) { ctx.beginPath(); ctx.moveTo(x + i * stepX, y); ctx.lineTo(x, y + i * stepY); ctx.stroke(); } break; case 'horizontal': default: for (let posY = y; posY < y + height; posY += spacing) { ctx.beginPath(); ctx.moveTo(x, posY); ctx.lineTo(x + width, posY); ctx.stroke(); } break; } // Restaura o estado ctx.restore(); } /** * Aplica um efeito de brilho (glow) * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {number} radius - Raio dos cantos * @param {string} color - Cor do brilho (hexadecimal) * @param {number} blurSize - Tamanho do desfoque */ function applyGlow(ctx, x, y, width, height, radius = 10, color = "#3498DB", blurSize = 20) { // Salva o estado atual ctx.save(); // Aplica o efeito de brilho ctx.shadowColor = color; ctx.shadowBlur = blurSize; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; // Desenha a forma com o brilho ctx.fillStyle = color; roundRect(ctx, x, y, width, height, radius, true, false); // Restaura o estado ctx.restore(); } /** * Aplica um efeito de textura de ruído * @param {Object} ctx - Contexto de renderização 2D * @param {number} x - Posição X * @param {number} y - Posição Y * @param {number} width - Largura * @param {number} height - Altura * @param {number} opacity - Opacidade do ruído (0-1) * @param {string} color - Cor do ruído (hexadecimal) */ function applyNoiseTexture(ctx, x, y, width, height, opacity = 0.1, color = "#000000") { // Cria um canvas temporário para o ruído const tempCanvas = document.createElement('canvas'); tempCanvas.width = width; tempCanvas.height = height; const tempCtx = tempCanvas.getContext('2d'); // Cria os dados da imagem const imageData = tempCtx.createImageData(width, height); const data = imageData.data; // Preenche os dados com ruído for (let i = 0; i < data.length; i += 4) { const value = Math.random() * 255; data[i] = value; // R data[i + 1] = value; // G data[i + 2] = value; // B data[i + 3] = Math.random() * 255 * opacity; // A } // Aplica os dados da imagem tempCtx.putImageData(imageData, 0, 0); // Desenha o ruído no contexto principal ctx.save(); ctx.globalAlpha = opacity; ctx.drawImage(tempCanvas, x, y, width, height); ctx.restore(); } /** * Aplica um efeito de recorte de imagem em forma de texto * @param {Object} ctx - Contexto de renderização 2D * @param {string} text - Texto a ser usado como máscara * @param {number} x - Posição X * @param {number} y - Posição Y * @param {Object} image - Imagem a ser recortada * @param {string} font - Fonte do texto */ function applyTextClipping(ctx, text, x, y, image, font) { // Salva o estado atual ctx.save(); // Define a fonte ctx.font = font; // Cria o caminho do texto ctx.fillStyle = "#000000"; ctx.textBaseline = "top"; ctx.fillText(text, x, y); // Usa o texto como máscara de recorte ctx.globalCompositeOperation = "source-in"; // Desenha a imagem ctx.drawImage(image, x, y); // Restaura o estado ctx.restore(); } // --- Exportações --- module.exports = { applyGlassmorphism, applyNeomorphism, applyMultiColorGradient, applyDotPattern, applyLinePattern, applyGlow, applyNoiseTexture, applyTextClipping };