(ctx, data, options)
| 813 | |
| 814 | // 渲染热力图(自定义实现) |
| 815 | function renderHeatmap(ctx, data, options) { |
| 816 | // 清除Canvas |
| 817 | ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height); |
| 818 | |
| 819 | // 设置尺寸和边距 |
| 820 | const margin = { |
| 821 | top: 50, |
| 822 | right: 30, |
| 823 | bottom: 50, |
| 824 | left: 60 |
| 825 | }; |
| 826 | |
| 827 | const width = ctx.canvas.width - margin.left - margin.right; |
| 828 | const height = ctx.canvas.height - margin.top - margin.bottom; |
| 829 | |
| 830 | // 获取数据 |
| 831 | const rows = data.labels; |
| 832 | const columns = data.datasets.map(dataset => dataset.label); |
| 833 | |
| 834 | // 创建值矩阵 |
| 835 | const matrix = []; |
| 836 | rows.forEach((_, rowIndex) => { |
| 837 | const row = []; |
| 838 | data.datasets.forEach(dataset => { |
| 839 | row.push(dataset.data[rowIndex]); |
| 840 | }); |
| 841 | matrix.push(row); |
| 842 | }); |
| 843 | |
| 844 | // 找出最大值和最小值 |
| 845 | const allValues = matrix.flat(); |
| 846 | const min = Math.min(...allValues); |
| 847 | const max = Math.max(...allValues); |
| 848 | |
| 849 | // 绘制标题 |
| 850 | if (options.plugins && options.plugins.title && options.plugins.title.display) { |
| 851 | ctx.textAlign = 'center'; |
| 852 | ctx.font = '18px Arial'; |
| 853 | ctx.fillStyle = '#333'; |
| 854 | ctx.fillText(options.plugins.title.text, ctx.canvas.width / 2, 25); |
| 855 | } |
| 856 | |
| 857 | // 绘制单元格和标签 |
| 858 | const cellWidth = width / columns.length; |
| 859 | const cellHeight = height / rows.length; |
| 860 | |
| 861 | // 行标签(Y轴) |
| 862 | ctx.textAlign = 'right'; |
| 863 | ctx.textBaseline = 'middle'; |
| 864 | ctx.font = '12px Arial'; |
| 865 | ctx.fillStyle = '#666'; |
| 866 | |
| 867 | rows.forEach((label, i) => { |
| 868 | const y = margin.top + i * cellHeight + cellHeight / 2; |
| 869 | ctx.fillText(label, margin.left - 10, y); |
| 870 | }); |
| 871 | |
| 872 | // 列标签(X轴) |
no test coverage detected