Error: Could not load required libraries. The tool cannot function.
';
return;
}
// --- GLOBAL VARIABLES ---
let seo_radarChart, seo_barChart;
const TABS = ['analysisDashboardTab', 'dataConfigTab'];
let seo_currentTabIndex = 0;
const METRIC_LABELS = ['Domain Strength', 'Referring Domains', 'Organic Keywords', 'Monthly Traffic', 'Traffic Value ($)'];
const METRIC_KEYS = ['domainStrength', 'referringDomains', 'organicKeywords', 'monthlyTraffic', 'trafficValue'];
// USA-relevant sample data for the home improvement sector
const sampleData = [
{ website: 'homedepot.com', domainStrength: 92, referringDomains: 165000, organicKeywords: 45000000, monthlyTraffic: 180000000, trafficValue: 150000000 },
{ website: 'lowes.com', domainStrength: 89, referringDomains: 95000, organicKeywords: 35000000, monthlyTraffic: 130000000, trafficValue: 110000000 },
{ website: 'acehardware.com', domainStrength: 78, referringDomains: 25000, organicKeywords: 5000000, monthlyTraffic: 20000000, trafficValue: 15000000 },
{ website: 'wayfair.com', domainStrength: 86, referringDomains: 88000, organicKeywords: 55000000, monthlyTraffic: 115000000, trafficValue: 95000000 },
];
// --- INITIALIZATION ---
function seo_initialize() {
seo_populateConfigForm(sampleData);
document.getElementById('analysis-date-input').valueAsDate = new Date();
seo_processDataAndUpdateDashboard();
seo_updateNavButtons();
}
// --- DATA CONFIGURATION ---
function seo_populateConfigForm(data) {
const tableBody = document.getElementById('seo-data-input-table');
tableBody.innerHTML = '';
data.forEach((competitor, index) => seo_add_competitor_row(competitor, index === 0));
}
window.seo_add_competitor_row = function(data = {}, isYourSite = false) {
const tableBody = document.getElementById('seo-data-input-table');
if (!isYourSite && tableBody.rows.length >= 5) {
alert("You can add a maximum of 4 competitors.");
return;
}
const row = tableBody.insertRow();
row.innerHTML = `
|
|
|
|
|
|
${isYourSite ? 'Your Website' : ''} |
`;
if (isYourSite) row.classList.add('your-site-config');
}
// --- DATA PROCESSING & DASHBOARD UPDATE ---
window.seo_processDataAndUpdateDashboard = function() {
const data = seo_collectData();
const analysisDate = new Date(document.getElementById('analysis-date-input').value).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
document.getElementById('analysis-date-display').textContent = `Analysis Date: ${analysisDate}`;
seo_updateDashboard(data);
seo_changeTab('analysisDashboardTab');
}
function seo_collectData() {
const rows = document.getElementById('seo-data-input-table').rows;
const data = [];
for (let row of rows) {
const inputs = row.querySelectorAll('input');
data.push({
website: inputs[0].value,
domainStrength: parseFloat(inputs[1].value) || 0,
referringDomains: parseFloat(inputs[2].value) || 0,
organicKeywords: parseFloat(inputs[3].value) || 0,
monthlyTraffic: parseFloat(inputs[4].value) || 0,
trafficValue: parseFloat(inputs[5].value) || 0
});
}
return data;
}
function seo_updateDashboard(data) {
const normalizedData = seo_normalizeData(data);
seo_updateRadarChart(data.map(d => d.website), normalizedData);
seo_updateBarChart(); // Called without args to use current state
seo_updateResultsTable(data);
}
// This is CRITICAL for the radar chart to be useful, as metrics have different scales.
function seo_normalizeData(data) {
const maxValues = {};
METRIC_KEYS.forEach(key => {
maxValues[key] = Math.max(...data.map(d => d[key]), 1); // Avoid division by zero
});
return data.map(d =>
METRIC_KEYS.map(key => (d[key] / maxValues[key]) * 100)
);
}
// --- CHART UPDATES ---
function seo_updateRadarChart(labels, normalizedData) {
const ctx = document.getElementById('seo-radar-chart');
if (seo_radarChart) seo_radarChart.destroy();
const datasets = normalizedData.map((d, i) => {
const colors = ['#007bff', '#dc3545', '#ffc107', '#28a745', '#6f42c1'];
const color = colors[i % colors.length];
return {
label: labels[i],
data: d,
borderColor: color,
backgroundColor: `${color}33`, // semi-transparent fill
pointBackgroundColor: color
};
});
seo_radarChart = new Chart(ctx, {
type: 'radar',
data: { labels: METRIC_LABELS, datasets },
options: {
responsive: true,
maintainAspectRatio: false,
scales: { r: { suggestedMin: 0, suggestedMax: 100, pointLabels: { font: { size: 12 } } } },
plugins: { legend: { position: 'top' } }
}
});
}
window.seo_updateBarChart = function() {
const data = seo_collectData();
const selectedMetric = document.getElementById('bar-chart-metric-selector').value;
const metricIndex = METRIC_KEYS.indexOf(selectedMetric);
const ctx = document.getElementById('seo-bar-chart');
if (seo_barChart) seo_barChart.destroy();
const colors = ['#007bff', '#dc3545', '#ffc107', '#28a745', '#6f42c1'];
const backgroundColors = data.map((d, i) => colors[i % colors.length]);
seo_barChart = new Chart(ctx, {
type: 'bar',
data: {
labels: data.map(d => d.website),
datasets: [{
label: METRIC_LABELS[metricIndex],
data: data.map(d => d[selectedMetric]),
backgroundColor: backgroundColors
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
indexAxis: 'y',
scales: { x: { beginAtZero: true } },
plugins: { legend: { display: false } }
}
});
}
// --- TABLE UPDATE ---
function seo_updateResultsTable(data) {
const head = document.getElementById('seo-results-table-head');
const body = document.getElementById('seo-results-table-body');
head.innerHTML = '';
body.innerHTML = '';
const yourSiteData = data[0];
if (!yourSiteData) return;
// Create header
const headerRow = head.insertRow();
headerRow.innerHTML = `
Competitor | ` + METRIC_LABELS.map(l => `
${l} | `).join('') + METRIC_LABELS.map(l => `
${l} (Gap) | `).join('');
// Create data rows
data.forEach((competitor, index) => {
const row = body.insertRow();
if (index === 0) {
row.classList.add('your-site-row');
let cells = `
${competitor.website} (You) | `;
METRIC_KEYS.forEach(key => cells += `
${competitor[key].toLocaleString()} | `);
cells += `
- | `;
row.innerHTML = cells;
} else {
let cells = `
${competitor.website} | `;
METRIC_KEYS.forEach(key => cells += `
${competitor[key].toLocaleString()} | `);
METRIC_KEYS.forEach(key => {
const gap = yourSiteData[key] - competitor[key];
const gapClass = gap > 0 ? 'gap-positive' : gap < 0 ? 'gap-negative' : '';
cells += `
${gap.toLocaleString()} | `;
});
row.innerHTML = cells;
}
});
}
// --- PDF EXPORT ---
window.seo_downloadPDF = function() {
try {
const { jsPDF } = window.jspdf;
const doc = new jsPDF('landscape');
const data = seo_collectData();
doc.setFontSize(20);
doc.setTextColor('#004085');
doc.text("SEO Competitor Analysis Report", doc.internal.pageSize.getWidth() / 2, 20, { align: 'center' });
const analysisDate = new Date(document.getElementById('analysis-date-input').value).toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });
doc.setFontSize(12);
doc.setTextColor('#6c757d');
doc.text(`Analysis Date: ${analysisDate}`, doc.internal.pageSize.getWidth() / 2, 28, { align: 'center' });
const radarCanvas = document.getElementById('seo-radar-chart').toDataURL('image/png', 1.0);
const barCanvas = document.getElementById('seo-bar-chart').toDataURL('image/png', 1.0);
doc.addImage(radarCanvas, 'PNG', 15, 40, 130, 130);
doc.addImage(barCanvas, 'PNG', 155, 40, 125, 130);
const tableHead = [
['Website', ...METRIC_LABELS]
];
const tableBody = data.map(site => [
site.website,
site.domainStrength.toLocaleString(),
site.referringDomains.toLocaleString(),
site.organicKeywords.toLocaleString(),
site.monthlyTraffic.toLocaleString(),
`$${site.trafficValue.toLocaleString()}`
]);
doc.autoTable({
head: tableHead,
body: tableBody,
startY: 180,
theme: 'grid',
headStyles: { fillColor: [0, 123, 255] },
didDrawCell: (data) => {
if (data.row.index === 0 && data.section === 'body') {
doc.setFillColor(207, 226, 255); // Highlight 'Your Site' row
}
}
});
doc.save('SEO_Competitor_Analysis_Report.pdf');
} catch(e) {
console.error("PDF generation failed:", e);
alert("An error occurred generating the PDF report.");
}
}
// --- TABBING & NAVIGATION ---
window.seo_changeTab = function(tabId) {
document.querySelectorAll('.seo-tab-content').forEach(c => c.classList.remove('active'));
document.querySelectorAll('.seo-tab-button').forEach(b => b.classList.remove('active'));
document.getElementById(tabId).classList.add('active');
const activeButton = Array.from(document.querySelectorAll('.seo-tab-button')).find(btn => btn.getAttribute('onclick').includes(tabId));
if (activeButton) activeButton.classList.add('active');
seo_currentTabIndex = TABS.indexOf(tabId);
seo_updateNavButtons();
}
window.seo_navigateTabs = function(direction) {
let newIndex = seo_currentTabIndex;
if (direction === 'next') newIndex = Math.min(newIndex + 1, TABS.length - 1);
else if (direction === 'prev') newIndex = Math.max(newIndex - 1, 0);
seo_changeTab(TABS[newIndex]);
}
function seo_updateNavButtons() {
const prevBtn = document.getElementById('seo-prev-btn');
const nextBtn = document.getElementById('seo-next-btn');
if(prevBtn) prevBtn.disabled = seo_currentTabIndex === 0;
if(nextBtn) nextBtn.disabled = seo_currentTabIndex === TABS.length - 1;
}
// --- KICK IT OFF ---
seo_initialize();
});