使用Chart.js制作含总访客与新访客信息的非堆叠条形图求助
Hey, great question! You don't need to switch to D3.js for this—Chart.js can absolutely handle your requirement with a few custom tweaks. Let me walk you through how to make this work.
Your key needs are:
- Bar height equals total visitors (not the sum of total + new)
- Tooltip shows both total and new visitor counts
- Optional: Display new visitor numbers directly on each bar
Core Approach
We’ll use a primary dataset for total visitors (to control bar height), store new visitor data as a custom property on the dataset, then use Chart.js’s built-in callback functions and custom plugins to add the extra info you need.
Step-by-Step Implementation
1. Prepare Your Data
First, split your raw combined data into separate arrays for total and new visitors:
const rawVisitorData = [[20,15], [25,10], [30,15]]; const totalVisitors = rawVisitorData.map(item => item[0]); const newVisitors = rawVisitorData.map(item => item[1]); const dateLabels = getDataAttributes(data, 'data-date'); // Your custom date fetching function
2. Configure the Chart
Here’s the full Chart.js configuration that meets all your requirements:
const visitorChart = new Chart(document.getElementById('visitor-chart'), { type: 'bar', data: { labels: dateLabels, datasets: [{ label: 'Total Visitors', data: totalVisitors, backgroundColor: 'rgba(54, 162, 235, 0.7)', borderColor: 'rgba(54, 162, 235, 1)', borderWidth: 1, // Store new visitor data as a custom property newVisitors: newVisitors }] }, options: { responsive: true, scales: { y: { beginAtZero: true, title: { display: true, text: 'Total Visitors' } }, x: { title: { display: true, text: 'Date' } } }, plugins: { // Customize tooltip to show both values tooltip: { callbacks: { title: (context) => context[0].label, label: (context) => { const total = context.parsed.y; const newCount = context.dataset.newVisitors[context.dataIndex]; return [ `Total Visitors: ${total}`, `New Visitors: ${newCount}` ]; } } }, // Customize legend to show both metrics legend: { labels: { generateLabels: () => [ { text: 'Total Visitors', fillStyle: 'rgba(54, 162, 235, 0.7)', strokeStyle: 'rgba(54, 162, 235, 1)' }, { text: 'New Visitors', fillStyle: 'rgba(255, 99, 132, 0.7)', strokeStyle: 'rgba(255, 99, 132, 1)' } ] } } }, // Add a custom plugin to draw new visitor counts on bars plugins: [ { afterDraw: (chart) => { const ctx = chart.ctx; chart.data.datasets.forEach((dataset) => { const meta = chart.getDatasetMeta(0); meta.data.forEach((bar, index) => { const newCount = dataset.newVisitors[index]; // Draw text in the middle of the bar ctx.fillStyle = '#222'; ctx.font = '12px sans-serif'; ctx.textAlign = 'center'; ctx.fillText(`New: ${newCount}`, bar.x, bar.y + 20); }); }); } } ] } });
3. Key Features Explained
- Bar Height Control: The primary dataset uses only total visitor numbers, so bars will always match the total count (no stacking).
- Custom Tooltip: The
tooltip.callbacks.labelfunction pulls both total and new visitor data to display in the tooltip. - On-Bar Labels: The custom
afterDrawplugin draws the new visitor count directly on each bar—you can adjust the position, font, or color by modifying thefillTextparameters. - Custom Legend: We generate a legend that includes both metrics, even though we only have one dataset.
Should You Switch to D3.js?
For this specific use case, Chart.js is more than sufficient. It’s faster to set up, requires less code, and handles responsive design and basic interactions out of the box.
D3.js is a better choice if you need highly customized, non-standard visualizations (like complex interactive maps, network graphs, or custom animations) that Chart.js doesn’t support natively. But for your bar chart requirement, sticking with Chart.js will save you time and effort.
内容的提问来源于stack exchange,提问作者Marius Slovikas

