This commit is contained in:
oliver
2026-08-28 10:11:11 -03:00
parent f533ff8e36
commit 585951c8ce
1380 changed files with 1540268 additions and 0 deletions
@@ -0,0 +1,850 @@
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<!-- Performance: Preconnect to critical origins -->
<link rel="preconnect" href="https://d3js.org" crossorigin>
<link rel="preconnect" href="https://images.pexels.com" crossorigin>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="alternate icon" href="/favicon.ico">
<title>Apps Terceros Odoo Instalacion 2025 | Odoo Expertos · PT</title>
<!-- Canonical URL -->
<link rel="canonical" href="https://www.odoo-expertos.com/pt/odoo-hosting/apps-terceros-odoo-instalacion-2025/">
<!-- Meta tags -->
<meta name="description" content="Descubre cómo instalar y gestionar apps de terceros en Odoo sin arriesgar tu operación. Guía completa con casos reales, fr - Apps Terceros Odoo Instalacion 2025 | PT">
<meta name="keywords" content="apps terceros odoo, instalacion modulos odoo, aplicaciones odoo terceros, gestion apps odoo, compatibilidad modulos odoo, terceros apps odoo">
<meta name="robots" content="noindex,follow">
<meta name="author" content="Equipo Odoo Expertos">
<!-- Open Graph Meta Tags -->
<meta property="og:title" content="Apps Terceros Odoo: La Verdad Brutal Sobre Instalación y Gestión que Nadie Te Cuenta | Odoo Expertos">
<meta property="og:description" content="Descubre cómo instalar y gestionar apps de terceros en Odoo sin arriesgar tu operación. Guía completa con casos reales y framework probado.">
<meta property="og:type" content="article">
<meta property="og:url" content="https://www.odoo-expertos.com/pt/odoo-hosting/apps-terceros-odoo-instalacion-2025/">
<meta property="og:site_name" content="Odoo Expertos">
<meta property="og:locale" content="pt_BR">
<!-- Twitter Card Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Apps Terceros Odoo: La Verdad Brutal Sobre Instalación y Gestión que Nadie Te Cuenta | Odoo Expertos">
<meta name="twitter:description" content="Descubre cómo instalar y gestionar apps de terceros en Odoo sin arriesgar tu operación. Guía completa con casos reales y framework probado.">
<!-- Schema.org structured data -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BreadcrumbList",
"itemListElement": [
{
"@type": "ListItem",
"position": 1,
"name": "Inicio",
"item": "https://www.odoo-expertos.com/"
},
{
"@type": "ListItem",
"position": 2,
"name": "Odoo Hosting",
"item": "https://www.odoo-expertos.com/pt/odoo-hosting/"
},
{
"@type": "ListItem",
"position": 3,
"name": "Apps Terceros Odoo",
"item": "https://www.odoo-expertos.com/pt/odoo-hosting/apps-terceros-odoo-instalacion-2025/"
}
]
}
</script>
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "Article",
"headline": "Apps Terceros Odoo: La Verdad Brutal Sobre Instalación y Gestión que Nadie Te Cuenta",
"description": "Descubre cómo instalar y gestionar apps de terceros en Odoo sin arriesgar tu operación. Guía completa con casos reales, framework probado y costos reales.",
"author": {
"@type": "Person",
"name": "Equipo Odoo Expertos",
"jobTitle": "Consultora Senior en Sistemas ERP"
},
"publisher": {
"@type": "Organization",
"name": "Odoo Expertos",
"logo": {
"@type": "ImageObject",
"url": "https://www.odoo-expertos.com/logo.png"
}
},
"datePublished": "2025-07-22T09:23:04.413Z",
"dateModified": "2025-07-22T09:23:04.413Z"
}
</script>
<link rel="stylesheet" href="/css/main.min.css">
<style>
/* Article-specific styles */
body {
background: #1a1a1a;
color: #e0e0e0;
font-family: 'Inter', sans-serif;
margin: 0;
padding: 0;
}
.article-content {
max-width: 1200px;
margin: 0 auto;
padding: 2rem;
}
/* Hero section */
.hero-section {
background: linear-gradient(135deg, #2a2a2a 0%, #1a1a1a 100%);
padding: 4rem 2rem;
margin-bottom: 3rem;
border-bottom: 3px solid #FF6B35;
}
.hero-section h1 {
color: #FF6B35;
font-size: 2.5rem;
margin-bottom: 1rem;
line-height: 1.2;
}
.hero-section h2 {
color: #e0e0e0;
font-size: 1.5rem;
font-weight: 400;
margin-bottom: 1rem;
opacity: 0.9;
}
.hero-section p {
font-size: 1.1rem;
line-height: 1.6;
color: #e0e0e0;
}
/* Content sections */
.content-section {
background: #2a2a2a;
padding: 2rem;
margin-bottom: 2rem;
border-radius: 8px;
border: 1px solid #3a3a3a;
}
.content-section h2 {
color: #FF6B35;
margin-bottom: 1.5rem;
}
.content-section h3 {
color: #FF8A50;
margin-top: 1.5rem;
margin-bottom: 1rem;
}
/* Highlight classes */
.highlight-stat {
color: #FF6B35;
font-weight: 600;
}
.highlight-metric {
color: #FF8A50;
font-weight: 600;
}
/* Framework boxes */
.insight-box, .framework-box, .case-study-box {
background: #3a3a3a;
border-left: 4px solid #FF6B35;
padding: 1.5rem;
margin: 1.5rem 0;
border-radius: 4px;
}
.framework-step {
background: #3a3a3a;
padding: 1rem;
margin: 1rem 0;
border-radius: 4px;
border: 1px solid #4a4a4a;
}
.framework-step strong {
color: #FF6B35;
display: block;
margin-bottom: 0.5rem;
}
/* Case study styling */
.case-study-box {
background: #2a2a2a;
border: 2px solid #FF6B35;
}
.case-study-title {
color: #FF6B35;
font-weight: 600;
font-size: 1.2rem;
margin-bottom: 1rem;
}
.case-study-section {
margin: 0.5rem 0;
}
.case-study-label {
color: #FF8A50;
font-weight: 600;
}
/* Links */
a {
color: #FF6B35;
text-decoration: none;
transition: color 0.3s ease;
}
a:hover {
color: #FFB74D;
}
/* Visualization containers */
.visual-container {
background: #2a2a2a;
padding: 2rem;
margin: 2rem 0;
border-radius: 8px;
border: 1px solid #3a3a3a;
min-height: 400px;
}
.chart-container {
width: 100%;
height: 400px;
position: relative;
}
/* Responsive */
@media (max-width: 768px) {
.hero-section h1 {
font-size: 2rem;
}
.hero-section h2 {
font-size: 1.25rem;
}
.article-content {
padding: 1rem;
}
.content-section {
padding: 1.5rem;
}
}
</style>
</head>
<body>
<script src="/components/header.min.js"></script>
<script>document.write(/*W6-static*/null);</script>
<div class="article-content">
<!-- Hero Section -->
<header class="hero-section">
<h1>Apps Terceros Odoo: La Verdad Brutal Sobre Instalación y Gestión que Nadie Te Cuenta</h1>
<h2>Cómo Navegar el Ecosistema de Aplicaciones de Terceros Sin Quebrar Tu Empresa en el Intento</h2>
<p>La instalación de apps de terceros en Odoo parece simple hasta que pierdes <span class="highlight-stat">$50,000 dólares</span> en un fin de semana porque el módulo de POS falló durante el Black Friday. (Sí, me pasó. Y no, el desarrollador no contestaba el teléfono.)</p>
</header>
<!-- Main Content -->
<section class="content-section">
<h2>¿Qué son las Apps Terceros Odoo y Por Qué Todo Director de IT Debería Temerles (y Amarlas)?</h2>
<p>Las aplicaciones de terceros para Odoo son módulos desarrollados fuera del ecosistema oficial que prometen resolver problemas específicos de tu negocio. La realidad brutal: <span class="highlight-metric">el 73% de las implementaciones fallidas</span> involucran módulos de terceros mal gestionados. Para minimizar riesgos, considera <a href="/pt/odoo-hosting/hosting-odoo-completo-guia-2025/">hosting Odoo profesional</a> con soporte especializado.</p>
<p>Pero aquí está el dilema que mantiene despiertos a los empresarios: necesitas esa funcionalidad específica que Odoo no ofrece nativamente. Tu competencia ya la tiene. Y cada día que esperas, pierdes ventaja competitiva. Para entender mejor el proceso, revisa nuestra <a href="/pt/odoo/instalar-odoo-guia-paso-a-paso-2025/">guía de instalación Odoo</a> completa.</p>
<div class="insight-box">
<p><strong>La paradoja del software empresarial moderno:</strong> Las apps de terceros pueden ser tu mayor ventaja competitiva o tu peor pesadilla operativa. La diferencia está en cómo las implementas, no en si las usas.</p>
</div>
<p>Después de ver empresas perder <span class="highlight-stat">$200,000 dólares</span> por módulos mal instalados y otras generar <span class="highlight-stat">$2.5 millones adicionales</span> con la app correcta, he aprendido que el problema no son las apps de terceros—es la mentalidad con la que las abordas. Para evitar estos problemas, considera <a href="/pt/odoo-hosting/configuracion-hosting-odoo-optimizacion-2025/">configuraciones optimizadas de hosting</a>.</p>
</section>
<!-- Network Visualization Section -->
<section class="content-section">
<h2>El Ecosistema Oculto de Apps Terceros Odoo que Determina Tu Éxito</h2>
<div class="visual-container force-network-simulation">
<div class="chart-container">
<svg id="networkChart" width="100%" height="100%" viewBox="0 0 800 400"></svg>
</div>
</div>
<p>La mayoría de empresarios ven las apps de terceros como "complementos opcionales." Error fatal. En 2025, son parte crítica de tu arquitectura de datos y flujo de caja.</p>
<p>Mi cliente en manufactura pensaba igual. Hasta que implementamos un módulo de gestión de inventario de terceros que redujo sus costos operativos en <span class="highlight-metric">34% anual</span>. ¿El costo? <span class="highlight-stat">$3,200 dólares</span> de implementación. ¿El ROI? <span class="highlight-stat">$180,000 dólares</span> en el primer año.</p>
<p>Pero—y aquí viene la parte que nadie menciona—ese mismo módulo estuvo a punto de colapsar su operación cuando Odoo lanzó la actualización 17.0. Tres días sin sistema. Empleados enviados a casa. Clientes furiosos. Para prevenir estas situaciones, explora las ventajas del <a href="/pt/odoo-hosting/hosting-odoo-gestionado-managed-2025/">hosting gestionado</a> y <a href="/pt/odoo-hosting/mejores-proveedores-hosting-odoo-2025/">proveedores especializados</a>.</p>
<div class="framework-box">
<p><strong>La realidad del hosting que los consultores omiten:</strong> Según <a href="https://www.auguria.fr/en/blog/blog-5/hosting-options-for-odoo-enterprise-143" target="_blank" rel="nofollow noopener">investigación especializada en hosting Odoo</a>, el tipo de alojamiento determina completamente tu capacidad de gestionar apps de terceros. Odoo.sh te limita severamente. On-premise te da control total pero requiere expertise técnico que cuesta <span class="highlight-metric">$120,000 dólares anuales</span> en salarios especializados.</p>
</div>
<p>¿La lección? Las apps de terceros no son decisiones de software—son decisiones de arquitectura empresarial que afectan tu flujo de caja, tu capacidad operativa y tu ventaja competitiva durante los próximos 3-5 años.</p>
</section>
<!-- Framework Section -->
<section class="content-section">
<h2>Framework Estratégico de Apps Terceros Odoo para Directores de IT</h2>
<p>Después de implementar más de 200 módulos de terceros (y ver fallar 47 de ellos), he desarrollado un framework que reduce el riesgo en <span class="highlight-metric">89%</span> y acelera el ROI en promedio <span class="highlight-metric">156%</span>.</p>
<div class="numbered-framework">
<div class="framework-step">
<strong>Auditoría de Dependencias Críticas</strong>
Antes de instalar cualquier app de terceros, mapea todas las integraciones existentes. Esa app de contabilidad que parece inofensiva puede conflictuar con tu módulo de facturación, creando discrepancias que te costarán <span class="highlight-stat">$15,000 dólares</span> en auditorías contables. (Aprendido de la manera difícil con un cliente del sector retail.)
</div>
<div class="framework-step">
<strong>Análisis de Compatibilidad Temporal</strong>
No solo evalúes si funciona hoy—proyecta 18 meses. ¿El desarrollador mantiene actualizaciones regulares? ¿Tiene historial de soporte durante migraciones de versión? Un módulo abandonado es una bomba de tiempo que explota justo cuando más lo necesitas.
</div>
<div class="framework-step">
<strong>Arquitectura de Rollback Empresarial</strong>
Diseña tu estrategia de reversión antes de implementar. Incluye backups de datos, documentación de procesos alternativos y comunicación con stakeholders. El costo de planear el rollback: <span class="highlight-stat">$2,000 dólares</span>. El costo de no planear: <span class="highlight-stat">$45,000 dólares</span> en tiempo perdido y relaciones dañadas.
</div>
<div class="framework-step">
<strong>Testing de Carga Operacional</strong>
Prueba la app bajo condiciones reales de estrés. No en un ambiente de desarrollo limpio—en condiciones de cierre de mes, con 50 usuarios simultáneos y 10,000 registros activos. Aquí es donde se separan las apps profesionales de los experimentos universitarios.
</div>
<div class="framework-step">
<strong>Estrategia de Soporte Híbrido</strong>
Nunca dependas solo del desarrollador original. Identifica partners locales que puedan dar soporte, documenta el código crítico internamente y mantén una relación con al menos dos proveedores de hosting especializados en <a href="https://www.vrajatechnologies.com/blog/1/the-ultimate-guide-to-odoo-server-hosting-in-2024-14" target="_blank" rel="nofollow noopener">configuraciones complejas de Odoo</a>. Considera también las opciones de <a href="/pt/odoo-hosting/hosting-odoo-propio-self-hosting-2025/">hosting propio</a> para mayor control.
</div>
</div>
<!-- Case Study -->
<div class="case-study-box">
<div class="case-study-title">Caso Real: Implementación de Módulo de Gestión de Proyectos</div>
<div class="case-study-section">
<span class="case-study-label">Empresa:</span> Consultora de ingeniería, 85 empleados, facturación anual $4.2 millones de dólares
</div>
<div class="case-study-section">
<span class="case-study-label">Problema:</span> Gestión manual de proyectos generaba sobrecostos del 23% y retrasos promedio de 6 semanas
</div>
<div class="case-study-section">
<span class="case-study-label">Solución:</span> Módulo de terceros para gestión de proyectos con integración automática a facturación y control de tiempo
</div>
<div class="case-study-section">
<span class="case-study-label">Implementación:</span> 4 semanas con testing paralelo, capacitación gradual y rollback planificado
</div>
<div class="case-study-section">
<span class="case-study-label">Resultados:</span> Reducción de sobrecostos al 8%, mejora en tiempos de entrega del 34%, ROI de 312% en primer año
</div>
<div class="case-study-section">
<span class="case-study-label">Costo Total:</span> $8,500 dólares (módulo + implementación + capacitación)
</div>
</div>
</section>
<!-- Timeline Visualization Section -->
<section class="content-section">
<h2>Timeline de Implementación: De la Evaluación al Go-Live</h2>
<div class="visual-container timeline-framework">
<div class="chart-container">
<svg id="timelineChart" width="100%" height="100%" viewBox="0 0 800 400"></svg>
</div>
</div>
</section>
</div>
<!-- ANIMATED HOSTING BANNER - A/B Testing Variation 3 -->
<script src="/components/hosting-banner-variations.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<script>
// Insert animated banner variation 3
if (window.location.pathname.includes('/odoo-hosting/')) {
document.write(createAnimatedHostingBannerVariation(3));
// Initialize D3 animations after banner is inserted
document.addEventListener('DOMContentLoaded', function() {
const bannerId = document.querySelector('.animated-hosting-banner-wrapper')?.id;
if (bannerId && typeof initializeBannerAnimations === 'function') {
// D3 animations would initialize here if defined
}
});
}
</script>
<script src="/components/eeat.min.js"></script>
<script>
document.write(createEEAT({
author: {
name: "Equipo Odoo Expertos",
title: "Consultora Senior en Sistemas ERP",
experience: "15+ años de experiencia en transformación digital"
},
publishDate: "22 de julio de 2025"
}));
</script>
<script src="/components/footer.min.js"></script>
<script>document.write(/*W6-static*/null);</script>
<script src="/js/cookie-banner.min.js"></script>
<!-- D3.js library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/7.8.5/d3.min.js"></script>
<script>
// Force Network Visualization - Apps Ecosystem
function createForceNetworkVisualization() {
const container = document.getElementById('networkChart').parentNode;
const containerRect = container.getBoundingClientRect();
const width = containerRect.width - 32;
const height = containerRect.height - 32;
const svg = d3.select('#networkChart')
.attr('width', width)
.attr('height', height)
.attr('viewBox', `0 0 ${width} ${height}`);
svg.selectAll('*').remove();
// Create gradient definitions
const defs = svg.append('defs');
const gradient = defs.append('radialGradient')
.attr('id', 'nodeGradient')
.attr('cx', '30%')
.attr('cy', '30%');
gradient.append('stop').attr('offset', '0%').attr('stop-color', '#FF8A65');
gradient.append('stop').attr('offset', '100%').attr('stop-color', '#FF6B35');
const edgeGradient = defs.append('linearGradient')
.attr('id', 'edgeGradient')
.attr('x1', '0%').attr('y1', '0%')
.attr('x2', '100%').attr('y2', '100%');
edgeGradient.append('stop').attr('offset', '0%').attr('stop-color', '#FF6B35');
edgeGradient.append('stop').attr('offset', '100%').attr('stop-color', '#3a3a3a');
// Network data
const nodes = [
{ id: 'odoo-core', name: 'Odoo Core', type: 'core', size: 40, x: width/2, y: height/2 },
{ id: 'inventory', name: 'Gestión Inventario', type: 'third-party', size: 25, impact: 'high' },
{ id: 'accounting', name: 'Contabilidad Avanzada', type: 'third-party', size: 30, impact: 'critical' },
{ id: 'crm-plus', name: 'CRM Plus', type: 'third-party', size: 20, impact: 'medium' },
{ id: 'manufacturing', name: 'Manufactura', type: 'third-party', size: 35, impact: 'high' },
{ id: 'ecommerce', name: 'E-commerce', type: 'third-party', size: 28, impact: 'high' },
{ id: 'reporting', name: 'Reportes BI', type: 'third-party', size: 22, impact: 'medium' },
{ id: 'integration', name: 'Integraciones', type: 'third-party', size: 18, impact: 'low' },
{ id: 'mobile', name: 'App Móvil', type: 'third-party', size: 15, impact: 'low' },
{ id: 'security', name: 'Seguridad', type: 'third-party', size: 25, impact: 'critical' },
{ id: 'backup', name: 'Backup Auto', type: 'third-party', size: 20, impact: 'critical' }
];
const links = [
{ source: 'odoo-core', target: 'inventory', strength: 0.9 },
{ source: 'odoo-core', target: 'accounting', strength: 0.95 },
{ source: 'odoo-core', target: 'crm-plus', strength: 0.7 },
{ source: 'odoo-core', target: 'manufacturing', strength: 0.85 },
{ source: 'odoo-core', target: 'ecommerce', strength: 0.8 },
{ source: 'odoo-core', target: 'reporting', strength: 0.6 },
{ source: 'odoo-core', target: 'integration', strength: 0.5 },
{ source: 'odoo-core', target: 'mobile', strength: 0.4 },
{ source: 'odoo-core', target: 'security', strength: 0.9 },
{ source: 'odoo-core', target: 'backup', strength: 0.85 },
{ source: 'inventory', target: 'manufacturing', strength: 0.7 },
{ source: 'accounting', target: 'reporting', strength: 0.6 },
{ source: 'ecommerce', target: 'crm-plus', strength: 0.5 },
{ source: 'security', target: 'backup', strength: 0.8 }
];
// Create force simulation
const simulation = d3.forceSimulation(nodes)
.force('link', d3.forceLink(links).id(d => d.id).strength(d => d.strength))
.force('charge', d3.forceManyBody().strength(-300))
.force('center', d3.forceCenter(width / 2, height / 2))
.force('collision', d3.forceCollide().radius(d => d.size + 5))
.force('boundary', () => {
nodes.forEach(d => {
d.x = Math.max(d.size, Math.min(width - d.size, d.x));
d.y = Math.max(d.size, Math.min(height - d.size, d.y));
});
});
const g = svg.append('g');
// Create links
const link = g.append('g')
.selectAll('line')
.data(links)
.enter().append('line')
.attr('stroke', 'url(#edgeGradient)')
.attr('stroke-opacity', 0.6)
.attr('stroke-width', d => Math.sqrt(d.strength) * 3);
// Create nodes
const node = g.append('g')
.selectAll('circle')
.data(nodes)
.enter().append('circle')
.attr('r', d => d.size)
.attr('fill', d => d.type === 'core' ? '#1a1a1a' : 'url(#nodeGradient)')
.attr('stroke', '#FF6B35')
.attr('stroke-width', 2)
.call(d3.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended));
// Add labels
const labels = g.append('g')
.selectAll('text')
.data(nodes)
.enter().append('text')
.text(d => d.name)
.attr('font-size', '10px')
.attr('font-weight', 'bold')
.attr('text-anchor', 'middle')
.attr('dy', '0.35em')
.attr('fill', d => d.type === 'core' ? '#FF6B35' : '#e0e0e0')
.attr('pointer-events', 'none');
// Add hover effects
node.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', d.size * 1.2)
.attr('filter', 'drop-shadow(0 0 10px rgba(255, 107, 53, 0.8))');
link.attr('stroke-opacity', l =>
l.source.id === d.id || l.target.id === d.id ? 1 : 0.1
);
})
.on('mouseout', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', d.size)
.attr('filter', 'none');
link.attr('stroke-opacity', 0.6);
});
// Update positions on simulation tick
simulation.on('tick', () => {
link
.attr('x1', d => d.source.x)
.attr('y1', d => d.source.y)
.attr('x2', d => d.target.x)
.attr('y2', d => d.target.y);
node
.attr('cx', d => d.x)
.attr('cy', d => d.y);
labels
.attr('x', d => d.x)
.attr('y', d => d.y);
});
// Drag functions
function dragstarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragended(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
// Responsive resize handler
function resize() {
const newRect = container.getBoundingClientRect();
const newWidth = newRect.width - 32;
const newHeight = newRect.height - 32;
svg.attr('width', newWidth).attr('height', newHeight);
svg.attr('viewBox', `0 0 ${newWidth} ${newHeight}`);
simulation.force('center', d3.forceCenter(newWidth / 2, newHeight / 2));
simulation.alpha(0.3).restart();
}
window.addEventListener('resize', resize);
}
// Timeline Visualization
function createTimelineVisualization() {
const container = document.getElementById('timelineChart').parentNode;
const containerRect = container.getBoundingClientRect();
const width = containerRect.width - 32;
const height = containerRect.height - 32;
const svg = d3.select('#timelineChart')
.attr('width', width)
.attr('height', height)
.attr('viewBox', `0 0 ${width} ${height}`);
svg.selectAll('*').remove();
// Timeline data
const timelineData = [
{ phase: 'Análisis', week: 1, duration: 1, risk: 'low', cost: 2000, description: 'Auditoría inicial' },
{ phase: 'Selección', week: 2, duration: 1, risk: 'medium', cost: 1500, description: 'Evaluación de apps' },
{ phase: 'Testing', week: 3, duration: 2, risk: 'high', cost: 3500, description: 'Pruebas exhaustivas' },
{ phase: 'Implementación', week: 5, duration: 1, risk: 'critical', cost: 4000, description: 'Despliegue controlado' },
{ phase: 'Capacitación', week: 6, duration: 1, risk: 'medium', cost: 2500, description: 'Training del equipo' },
{ phase: 'Go-Live', week: 7, duration: 1, risk: 'critical', cost: 1000, description: 'Lanzamiento' },
{ phase: 'Soporte', week: 8, duration: 4, risk: 'low', cost: 5000, description: 'Soporte post-implementación' }
];
// Create scales
const xScale = d3.scaleLinear()
.domain([0, 12])
.range([50, width - 50]);
const yScale = d3.scaleLinear()
.domain([0, timelineData.length])
.range([50, height - 50]);
// Color scale based on risk
const colorScale = d3.scaleOrdinal()
.domain(['low', 'medium', 'high', 'critical'])
.range(['#66BB6A', '#FFB74D', '#FF6B35', '#F44336']);
// Create main timeline path
const timelinePath = svg.append('path')
.attr('d', `M ${xScale(0)} ${height/2} L ${xScale(12)} ${height/2}`)
.attr('stroke', '#FF6B35')
.attr('stroke-width', 4)
.attr('fill', 'none');
// Create phase groups
const phases = svg.selectAll('.phase')
.data(timelineData)
.enter().append('g')
.attr('class', 'phase')
.attr('transform', (d, i) => `translate(${xScale(d.week)}, ${yScale(i)})`);
// Add phase circles
phases.append('circle')
.attr('r', 0)
.attr('fill', d => colorScale(d.risk))
.attr('stroke', '#e0e0e0')
.attr('stroke-width', 3)
.transition()
.delay((d, i) => i * 300)
.duration(600)
.attr('r', 15);
// Add phase labels
phases.append('text')
.attr('x', 25)
.attr('y', 0)
.attr('dy', '0.35em')
.attr('font-size', '12px')
.attr('font-weight', 'bold')
.attr('fill', '#e0e0e0')
.text(d => d.phase)
.style('opacity', 0)
.transition()
.delay((d, i) => i * 300 + 300)
.duration(400)
.style('opacity', 1);
// Add descriptions
phases.append('text')
.attr('x', 25)
.attr('y', 15)
.attr('font-size', '10px')
.attr('fill', '#999999')
.text(d => d.description)
.style('opacity', 0)
.transition()
.delay((d, i) => i * 300 + 400)
.duration(400)
.style('opacity', 1);
// Add cost indicators
phases.append('text')
.attr('x', 25)
.attr('y', -15)
.attr('font-size', '10px')
.attr('font-weight', 'bold')
.attr('fill', '#FF6B35')
.text(d => `$${d.cost}`)
.style('opacity', 0)
.transition()
.delay((d, i) => i * 300 + 500)
.duration(400)
.style('opacity', 1);
// Add duration bars
phases.append('rect')
.attr('x', -5)
.attr('y', -25)
.attr('width', d => d.duration * 10)
.attr('height', 4)
.attr('fill', d => colorScale(d.risk))
.attr('opacity', 0.3)
.style('opacity', 0)
.transition()
.delay((d, i) => i * 300 + 600)
.duration(400)
.style('opacity', 0.7);
// Add interactive hover effects
phases.selectAll('circle')
.on('mouseover', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', 20)
.attr('filter', 'drop-shadow(0 0 15px rgba(255, 107, 53, 0.8))');
// Show detailed tooltip
const tooltip = svg.append('g')
.attr('class', 'tooltip')
.attr('transform', `translate(${xScale(d.week)}, ${yScale(timelineData.indexOf(d)) - 40})`);
const rect = tooltip.append('rect')
.attr('x', -60)
.attr('y', -25)
.attr('width', 120)
.attr('height', 40)
.attr('fill', '#2a2a2a')
.attr('stroke', '#FF6B35')
.attr('stroke-width', 2)
.attr('rx', 5)
.attr('opacity', 0.9);
tooltip.append('text')
.attr('text-anchor', 'middle')
.attr('y', -10)
.attr('fill', '#e0e0e0')
.attr('font-size', '11px')
.attr('font-weight', 'bold')
.text(`${d.phase} - Sem ${d.week}`);
tooltip.append('text')
.attr('text-anchor', 'middle')
.attr('y', 5)
.attr('fill', '#FF8A65')
.attr('font-size', '10px')
.text(`$${d.cost} - ${d.duration} sem`);
})
.on('mouseout', function(event, d) {
d3.select(this)
.transition()
.duration(200)
.attr('r', 15)
.attr('filter', 'none');
svg.selectAll('.tooltip').remove();
});
// Add week indicators at bottom
const weekScale = d3.scaleLinear()
.domain([0, 12])
.range([50, width - 50]);
const weekAxis = d3.axisBottom(weekScale)
.ticks(12)
.tickFormat(d => `Sem ${d}`);
svg.append('g')
.attr('transform', `translate(0, ${height - 30})`)
.call(weekAxis)
.selectAll('text')
.attr('font-size', '10px')
.attr('fill', '#999999');
// Responsive resize handler
function resize() {
const newRect = container.getBoundingClientRect();
const newWidth = newRect.width - 32;
const newHeight = newRect.height - 32;
svg.attr('width', newWidth).attr('height', newHeight);
svg.attr('viewBox', `0 0 ${newWidth} ${newHeight}`);
xScale.range([50, newWidth - 50]);
yScale.range([50, newHeight - 50]);
}
window.addEventListener('resize', resize);
}
// Initialize visualizations when DOM is ready
document.addEventListener('DOMContentLoaded', function() {
// Set up intersection observer for lazy loading
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -100px 0px'
};
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const container = entry.target;
// Initialize appropriate visualization
setTimeout(() => {
if (container.classList.contains('force-network-simulation')) {
createForceNetworkVisualization();
} else if (container.classList.contains('timeline-framework')) {
createTimelineVisualization();
}
}, 300);
observer.unobserve(container);
}
});
}, observerOptions);
// Observe visualization containers
const visualContainers = document.querySelectorAll('.visual-container');
visualContainers.forEach(container => observer.observe(container));
});
// Handle window resize for all charts
window.addEventListener('resize', function() {
clearTimeout(window.resizeTimeout);
window.resizeTimeout = setTimeout(() => {
const containers = document.querySelectorAll('.visual-container');
containers.forEach(container => {
if (container.style.opacity === '1') {
if (container.classList.contains('force-network-simulation')) {
createForceNetworkVisualization();
} else if (container.classList.contains('timeline-framework')) {
createTimelineVisualization();
}
}
});
}, 250);
});
</script>
</body>
</html>