Skip to content

Chart.js 图表样式和自定义

Chart.js 提供了丰富的样式自定义选项,允许开发者创建符合品牌风格和设计需求的图表。本章将详细介绍如何自定义 Chart.js 图表的样式和外观。

全局样式配置

1. 全局默认配置

可以通过修改 Chart.defaults 来设置全局默认样式:

javascript
// 设置全局默认配置
Chart.defaults.borderColor = '#ccc';
Chart.defaults.color = '#666';
Chart.defaults.font.family = 'Arial, sans-serif';
Chart.defaults.font.size = 14;
Chart.defaults.font.weight = 'normal';
Chart.defaults.responsive = true;
Chart.defaults.maintainAspectRatio = false;

// 创建图表时会使用这些全局默认值
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    }
    // options 中未指定的配置会使用全局默认值
});

2. 图表级别配置

在创建图表时,可以通过 options 参数进行样式配置:

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        // 图表级别的样式配置
        responsive: true,
        maintainAspectRatio: false,
        backgroundColor: '#f8f9fa',
        borderColor: '#dee2e6',
        borderWidth: 1,
        
        // 字体配置
        font: {
            family: 'Arial, sans-serif',
            size: 14,
            weight: 'normal',
            lineHeight: 1.2
        },
        
        // 布局配置
        layout: {
            padding: {
                top: 20,
                right: 20,
                bottom: 20,
                left: 20
            }
        }
    }
});

颜色自定义

1. 数据集颜色

可以为每个数据集设置不同的颜色:

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['一月', '二月', '三月', '四月', '五月', '六月'],
        datasets: [{
            label: '销售额',
            data: [12, 19, 3, 5, 2, 3],
            // 背景色
            backgroundColor: [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 205, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ],
            // 边框色
            borderColor: [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 205, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ],
            // 边框宽度
            borderWidth: 2
        }]
    }
});

2. 渐变色

可以使用 Canvas 的渐变功能创建渐变色效果:

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        labels: ['一月', '二月', '三月', '四月', '五月', '六月'],
        datasets: [{
            label: '销售额',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: function(context) {
                const chart = context.chart;
                const {ctx, chartArea} = chart;
                
                if (!chartArea) {
                    // 如果图表区域未定义,返回默认颜色
                    return 'rgba(54, 162, 235, 0.2)';
                }
                
                // 创建线性渐变
                const gradient = ctx.createLinearGradient(0, chartArea.top, 0, chartArea.bottom);
                gradient.addColorStop(0, 'rgba(54, 162, 235, 0.8)');
                gradient.addColorStop(1, 'rgba(54, 162, 235, 0.2)');
                
                return gradient;
            },
            borderColor: 'rgba(54, 162, 235, 1)',
            borderWidth: 2
        }]
    }
});

字体和文本样式

1. 标题样式

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        plugins: {
            title: {
                display: true,
                text: '月度销售数据',
                font: {
                    family: 'Arial, sans-serif',
                    size: 18,
                    weight: 'bold',
                    style: 'normal'
                },
                color: '#333',
                padding: {
                    top: 10,
                    bottom: 20
                }
            }
        }
    }
});

2. 图例样式

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        plugins: {
            legend: {
                display: true,
                position: 'top',
                align: 'center',
                labels: {
                    font: {
                        family: 'Arial, sans-serif',
                        size: 14,
                        weight: 'normal'
                    },
                    color: '#666',
                    padding: 10,
                    usePointStyle: true, // 使用点样式而不是方块
                    pointStyle: 'circle'
                }
            }
        }
    }
});

3. 工具提示样式

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        plugins: {
            tooltip: {
                enabled: true,
                backgroundColor: 'rgba(0, 0, 0, 0.8)',
                titleColor: '#fff',
                bodyColor: '#fff',
                borderColor: '#333',
                borderWidth: 1,
                cornerRadius: 6,
                displayColors: true,
                font: {
                    family: 'Arial, sans-serif',
                    size: 12,
                    weight: 'normal'
                },
                padding: 10,
                callbacks: {
                    title: function(tooltipItems) {
                        return '月份: ' + tooltipItems[0].label;
                    },
                    label: function(context) {
                        return context.dataset.label + ': ' + context.parsed.y + ' 万元';
                    }
                }
            }
        }
    }
});

坐标轴样式

1. 基本坐标轴配置

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        scales: {
            x: {
                // X轴标题
                title: {
                    display: true,
                    text: '月份',
                    color: '#666',
                    font: {
                        family: 'Arial, sans-serif',
                        size: 14,
                        weight: 'bold'
                    }
                },
                // 刻度线
                ticks: {
                    color: '#999',
                    font: {
                        family: 'Arial, sans-serif',
                        size: 12
                    },
                    callback: function(value, index, values) {
                        // 自定义刻度标签
                        return value + '月';
                    }
                },
                // 网格线
                grid: {
                    color: 'rgba(0, 0, 0, 0.1)',
                    lineWidth: 1
                }
            },
            y: {
                // Y轴标题
                title: {
                    display: true,
                    text: '销售额 (万元)',
                    color: '#666',
                    font: {
                        family: 'Arial, sans-serif',
                        size: 14,
                        weight: 'bold'
                    }
                },
                // 刻度线
                ticks: {
                    color: '#999',
                    font: {
                        family: 'Arial, sans-serif',
                        size: 12
                    },
                    beginAtZero: true,
                    callback: function(value, index, values) {
                        // 添加单位
                        return value + '万';
                    }
                },
                // 网格线
                grid: {
                    color: 'rgba(0, 0, 0, 0.1)',
                    lineWidth: 1
                }
            }
        }
    }
});

2. 坐标轴位置和显示

javascript
const myChart = new Chart(ctx, {
    type: 'line',
    data: {
        // ... 数据配置
    },
    options: {
        scales: {
            x: {
                position: 'bottom', // 'top', 'bottom'
                display: true,      // 是否显示坐标轴
                reverse: false,     // 是否反转坐标轴
            },
            y: {
                position: 'left',   // 'left', 'right'
                display: true,
                min: 0,            // 最小值
                max: 100,          // 最大值
                ticks: {
                    stepSize: 10   // 刻度步长
                }
            },
            // 第二个Y轴
            y1: {
                position: 'right',
                display: true,
                grid: {
                    drawOnChartArea: false // 不在图表区域绘制网格线
                }
            }
        }
    }
});

动画效果

1. 基本动画配置

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        animation: {
            duration: 1000,        // 动画持续时间(毫秒)
            easing: 'easeInOutQuart', // 缓动函数
            delay: 0,              // 延迟时间
            loop: false            // 是否循环
            
            // 动画属性配置
            // colors: {
            //     duration: 1000,
            //     easing: 'easeInOutQuart'
            // },
            // numbers: {
            //     duration: 1000,
            //     easing: 'easeInOutQuart'
            // }
        }
    }
});

2. 自定义动画

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        animation: {
            duration: 2000,
            easing: 'linear',
            onProgress: function(animation) {
                // 动画进行中的回调
                console.log('动画进度:', animation.currentStep / animation.numSteps);
            },
            onComplete: function(animation) {
                // 动画完成的回调
                console.log('动画完成');
            }
        }
    }
});

响应式设计

1. 基本响应式配置

javascript
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        responsive: true,           // 启用响应式
        maintainAspectRatio: true,  // 保持宽高比
        aspectRatio: 2,            // 宽高比 (width/height)
        
        // 响应式事件
        onResize: function(chart, size) {
            console.log('图表大小调整:', size);
        }
    }
});

2. 媒体查询样式

javascript
// 根据屏幕大小设置不同的配置
const config = {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        responsive: true,
        plugins: {
            legend: {
                position: window.innerWidth < 768 ? 'bottom' : 'top'
            }
        },
        scales: {
            x: {
                ticks: {
                    font: {
                        size: window.innerWidth < 768 ? 10 : 12
                    }
                }
            }
        }
    }
};

const myChart = new Chart(ctx, config);

// 监听窗口大小变化
window.addEventListener('resize', function() {
    // 更新图表配置
    myChart.options.plugins.legend.position = window.innerWidth < 768 ? 'bottom' : 'top';
    myChart.options.scales.x.ticks.font.size = window.innerWidth < 768 ? 10 : 12;
    myChart.update();
});

主题和样式变体

1. 创建自定义主题

javascript
// 定义主题配置
const darkTheme = {
    backgroundColor: '#222',
    borderColor: '#444',
    color: '#eee',
    font: {
        family: 'Arial, sans-serif',
        size: 14,
        weight: 'normal'
    },
    plugins: {
        title: {
            color: '#fff',
            font: {
                size: 18,
                weight: 'bold'
            }
        },
        legend: {
            labels: {
                color: '#ccc'
            }
        },
        tooltip: {
            backgroundColor: 'rgba(50, 50, 50, 0.9)',
            titleColor: '#fff',
            bodyColor: '#eee',
            borderColor: '#666'
        }
    },
    scales: {
        x: {
            ticks: {
                color: '#ccc'
            },
            grid: {
                color: 'rgba(255, 255, 255, 0.1)'
            }
        },
        y: {
            ticks: {
                color: '#ccc'
            },
            grid: {
                color: 'rgba(255, 255, 255, 0.1)'
            }
        }
    }
};

// 应用主题
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        ...darkTheme,
        responsive: true,
        scales: {
            y: {
                beginAtZero: true,
                ...darkTheme.scales.y
            },
            x: {
                ...darkTheme.scales.x
            }
        }
    }
});

2. 动态主题切换

javascript
// 定义多个主题
const themes = {
    light: {
        backgroundColor: '#fff',
        color: '#333',
        // ... 其他配置
    },
    dark: {
        backgroundColor: '#222',
        color: '#eee',
        // ... 其他配置
    }
};

// 创建图表时使用默认主题
let currentTheme = 'light';
const myChart = new Chart(ctx, {
    type: 'bar',
    data: {
        // ... 数据配置
    },
    options: {
        ...themes[currentTheme],
        responsive: true
    }
});

// 切换主题的函数
function switchTheme(themeName) {
    currentTheme = themeName;
    Object.assign(myChart.options, themes[themeName]);
    myChart.update();
}

// 使用示例
// switchTheme('dark'); // 切换到暗色主题

完整示例

以下是一个展示多种样式自定义效果的完整示例:

html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Chart.js 样式自定义示例</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
        }
        .chart-container {
            position: relative;
            height: 400px;
            margin: 20px 0;
        }
        .controls {
            text-align: center;
            margin: 20px 0;
        }
        button {
            margin: 5px;
            padding: 10px 20px;
            background-color: #007bff;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }
        button:hover {
            background-color: #0056b3;
        }
        .theme-selector {
            margin: 20px 0;
            text-align: center;
        }
        select {
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1 style="text-align: center;">Chart.js 样式自定义示例</h1>
        
        <div class="theme-selector">
            <label for="themeSelect">选择主题: </label>
            <select id="themeSelect">
                <option value="default">默认主题</option>
                <option value="dark">暗色主题</option>
                <option value="colorful">彩色主题</option>
            </select>
        </div>
        
        <div class="controls">
            <button onclick="toggleAnimation()">切换动画</button>
            <button onclick="changeColors()">更换颜色</button>
        </div>
        
        <div class="chart-container">
            <canvas id="myChart"></canvas>
        </div>
    </div>
    
    <script>
        // 定义主题配置
        const themes = {
            default: {
                backgroundColor: '#fff',
                color: '#333',
                plugins: {
                    title: {
                        color: '#333',
                        font: {
                            size: 18,
                            weight: 'bold'
                        }
                    },
                    legend: {
                        labels: {
                            color: '#666',
                            font: {
                                size: 14
                            }
                        }
                    },
                    tooltip: {
                        backgroundColor: 'rgba(0, 0, 0, 0.8)',
                        titleColor: '#fff',
                        bodyColor: '#fff'
                    }
                },
                scales: {
                    x: {
                        ticks: {
                            color: '#666'
                        },
                        grid: {
                            color: 'rgba(0, 0, 0, 0.1)'
                        }
                    },
                    y: {
                        ticks: {
                            color: '#666'
                        },
                        grid: {
                            color: 'rgba(0, 0, 0, 0.1)'
                        }
                    }
                }
            },
            dark: {
                backgroundColor: '#222',
                color: '#eee',
                plugins: {
                    title: {
                        color: '#fff',
                        font: {
                            size: 18,
                            weight: 'bold'
                        }
                    },
                    legend: {
                        labels: {
                            color: '#ccc',
                            font: {
                                size: 14
                            }
                        }
                    },
                    tooltip: {
                        backgroundColor: 'rgba(50, 50, 50, 0.9)',
                        titleColor: '#fff',
                        bodyColor: '#eee',
                        borderColor: '#666'
                    }
                },
                scales: {
                    x: {
                        ticks: {
                            color: '#ccc'
                        },
                        grid: {
                            color: 'rgba(255, 255, 255, 0.1)'
                        }
                    },
                    y: {
                        ticks: {
                            color: '#ccc'
                        },
                        grid: {
                            color: 'rgba(255, 255, 255, 0.1)'
                        }
                    }
                }
            },
            colorful: {
                backgroundColor: '#f8f9fa',
                color: '#333',
                plugins: {
                    title: {
                        color: '#e74c3c',
                        font: {
                            size: 18,
                            weight: 'bold'
                        }
                    },
                    legend: {
                        labels: {
                            color: '#3498db',
                            font: {
                                size: 14
                            }
                        }
                    },
                    tooltip: {
                        backgroundColor: 'rgba(52, 152, 219, 0.9)',
                        titleColor: '#fff',
                        bodyColor: '#fff',
                        borderColor: '#2980b9'
                    }
                },
                scales: {
                    x: {
                        ticks: {
                            color: '#27ae60'
                        },
                        grid: {
                            color: 'rgba(39, 174, 96, 0.2)'
                        }
                    },
                    y: {
                        ticks: {
                            color: '#27ae60'
                        },
                        grid: {
                            color: 'rgba(39, 174, 96, 0.2)'
                        }
                    }
                }
            }
        };
        
        // 创建图表
        const ctx = document.getElementById('myChart').getContext('2d');
        let myChart = new Chart(ctx, {
            type: 'bar',
            data: {
                labels: ['一月', '二月', '三月', '四月', '五月', '六月'],
                datasets: [{
                    label: '产品 A 销售额',
                    data: [12, 19, 3, 5, 2, 3],
                    backgroundColor: 'rgba(255, 99, 132, 0.2)',
                    borderColor: 'rgba(255, 99, 132, 1)',
                    borderWidth: 2
                }, {
                    label: '产品 B 销售额',
                    data: [8, 15, 7, 12, 9, 6],
                    backgroundColor: 'rgba(54, 162, 235, 0.2)',
                    borderColor: 'rgba(54, 162, 235, 1)',
                    borderWidth: 2
                }]
            },
            options: {
                ...themes.default,
                responsive: true,
                maintainAspectRatio: false,
                plugins: {
                    title: {
                        display: true,
                        text: '产品销售数据图表'
                    },
                    legend: {
                        position: 'top'
                    }
                },
                scales: {
                    y: {
                        beginAtZero: true,
                        title: {
                            display: true,
                            text: '销售额 (万元)'
                        }
                    },
                    x: {
                        title: {
                            display: true,
                            text: '月份'
                        }
                    }
                },
                animation: {
                    duration: 1000,
                    easing: 'easeInOutQuart'
                }
            }
        });
        
        // 主题切换
        document.getElementById('themeSelect').addEventListener('change', function() {
            const selectedTheme = this.value;
            Object.assign(myChart.options, themes[selectedTheme]);
            myChart.update();
        });
        
        // 切换动画
        let animationEnabled = true;
        function toggleAnimation() {
            animationEnabled = !animationEnabled;
            myChart.options.animation.duration = animationEnabled ? 1000 : 0;
            myChart.update();
        }
        
        // 更换颜色
        function changeColors() {
            const colors = [
                'rgba(255, 99, 132, 0.2)',
                'rgba(54, 162, 235, 0.2)',
                'rgba(255, 205, 86, 0.2)',
                'rgba(75, 192, 192, 0.2)',
                'rgba(153, 102, 255, 0.2)',
                'rgba(255, 159, 64, 0.2)'
            ];
            
            const borderColors = [
                'rgba(255, 99, 132, 1)',
                'rgba(54, 162, 235, 1)',
                'rgba(255, 205, 86, 1)',
                'rgba(75, 192, 192, 1)',
                'rgba(153, 102, 255, 1)',
                'rgba(255, 159, 64, 1)'
            ];
            
            // 随机打乱颜色数组
            shuffleArray(colors);
            shuffleArray(borderColors);
            
            myChart.data.datasets[0].backgroundColor = colors[0];
            myChart.data.datasets[0].borderColor = borderColors[0];
            myChart.data.datasets[1].backgroundColor = colors[1];
            myChart.data.datasets[1].borderColor = borderColors[1];
            
            myChart.update();
        }
        
        // 数组随机打乱函数
        function shuffleArray(array) {
            for (let i = array.length - 1; i > 0; i--) {
                const j = Math.floor(Math.random() * (i + 1));
                [array[i], array[j]] = [array[j], array[i]];
            }
        }
    </script>
</body>
</html>

通过本章的学习,你应该掌握了如何自定义 Chart.js 图表的样式和外观。在下一章中,我们将探讨 Chart.js 的高级功能。

本站内容仅供学习和研究使用。