Total Impressions
${analysis.totalImpressions.toLocaleString()}
Average CTR
${analysis.averageCtr}%
Average Position
${analysis.averagePosition}
`;
dashboardTableBody.innerHTML = '';
state.keywords.sort((a,b) => b.clicks - a.clicks).forEach(kw => {
const tr = document.createElement('tr');
tr.className = 'bg-white border-b hover:bg-gray-50';
tr.innerHTML = `
${kw.name} |
${kw.clicks.toLocaleString()} |
${kw.impressions.toLocaleString()} |
${kw.ctr.toFixed(2)}% |
${kw.position.toFixed(1)} |
`;
dashboardTableBody.appendChild(tr);
});
renderChart();
};
const renderChart = () => {
if (performanceChart) performanceChart.destroy();
const chartData = state.keywords.map(kw => ({
x: kw.position,
y: kw.ctr,
r: Math.log(kw.impressions + 1) * 3, // Bubble size based on impressions
label: kw.name
}));
performanceChart = new Chart(performanceChartCanvas, {
type: 'bubble',
data: {
datasets: [{
label: 'Keywords',
data: chartData,
backgroundColor: 'rgba(59, 130, 246, 0.5)',
borderColor: 'rgb(59, 130, 246)',
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
reverse: true,
title: { display: true, text: 'Average Position' }
},
y: {
beginAtZero: true,
title: { display: true, text: 'CTR (%)' }
}
},
plugins: {
legend: { display: false },
tooltip: {
callbacks: {
label: function(context) {
const d = context.raw;
return `${d.label}: Pos ${d.x.toFixed(1)}, CTR ${d.y.toFixed(1)}%`;
}
}
}
}
}
});
};
// --- Event Handlers ---
addKeywordBtn.addEventListener('click', () => createKeywordRow());
// --- Tab & Navigation Logic ---
function switchTab(targetTabId) {
if (currentTab === 'config') {
saveConfig();
}
currentTab = targetTabId;
tabs.forEach(tab => tab.classList.toggle('active', tab.dataset.tab === currentTab));
tabContents.forEach(content => content.classList.toggle('active', content.id === currentTab));
if (currentTab === 'dashboard') {
renderDashboard();
} else {
renderConfig();
}
updateNavButtons();
}
function updateNavButtons() {
if (currentTab === 'dashboard') {
nextBtn.textContent = 'Configure Data';
prevBtn.style.display = 'none';
pdfButtonContainer.style.display = 'block';
} else {
nextBtn.textContent = 'Update Dashboard';
prevBtn.style.display = 'inline-flex';
pdfButtonContainer.style.display = 'none';
}
}
tabs.forEach(tab => tab.addEventListener('click', () => switchTab(tab.dataset.tab)));
nextBtn.addEventListener('click', () => currentTab === 'dashboard' ? switchTab('config') : switchTab('dashboard'));
prevBtn.addEventListener('click', () => currentTab === 'config' ? switchTab('dashboard') : switchTab('config'));
// --- PDF Download ---
downloadPdfBtn.addEventListener('click', async () => {
const { jsPDF } = window.jspdf;
const doc = new jsPDF({ orientation: 'p', unit: 'mm', format: 'a4' });
const content = document.getElementById('pdf-content');
document.getElementById('pdf-date').textContent = `Report Generated: ${new Date().toLocaleString()}`;
const canvas = await html2canvas(content, { scale: 2 });
const imgData = canvas.toDataURL('image/jpeg', 1.0);
const imgProps = doc.getImageProperties(imgData);
const pdfWidth = doc.internal.pageSize.getWidth() - 28;
const pdfHeight = (imgProps.height * pdfWidth) / imgProps.width;
doc.addImage(imgData, 'JPEG', 14, 15, pdfWidth, pdfHeight);
document.getElementById('pdf-date').textContent = '';
doc.save(`GSC-Performance-Report-${new Date().toISOString().slice(0,10)}.pdf`);
});
// --- Initial Load ---
renderDashboard();
updateNavButtons();
});