如何在ChartJS中创建带张力的部分标签无值折线图
解决ChartJS进度折线图锯齿状问题
问题背景
我想用ChartJS制作一个展示进度随时间变化的折线图,数据库仅存储进度发生变化的日期及对应进度值,数据格式如下:
"progress": { "07.02.2020": 0, "29.02.2020": 1, "07.04.2020": 2, "07.05.2020": 3, "07.07.2020": 4, "07.08.2020": 5, "07.09.2020": 6, "07.11.2020": 7, "07.12.2020": 8, "07.01.2021": 9, "07.02.2022": 10, "30.02.2022": 11 }
我先通过以下脚本生成起始日期07.02.2020至结束日期30.02.2022之间的所有日期作为图表标签:
function addDatesToChart(startDate, endDate) { const currentDate = new Date(startDate.getTime()); console.log(currentDate); while (currentDate <= endDate) { chartData3.labels.push(new Date(currentDate).toLocaleDateString("et-EE", {year: "numeric", month: "2-digit", day: "2-digit"})); currentDate.setDate(currentDate.getDate() + 1); } }
随后用以下脚本为图表填充进度值,将无数据的日期填充为上一个进度值:
let lastGivenProgress = 0; let lastGivenProgressIndex = 0; for (let i = 0; i < chartData.labels.length; i++) { if (!(Object.keys(progress).includes(chartData.labels[i]))) { chartData.datasets[0].data.push(lastGivenProgress); } else { chartData.datasets[0].data.push(Object.values(data)[lastGivenProgressIndex++]); lastGivenProgress = Object.values(progress)[lastGivenProgressIndex]; } }
问题在于我希望折线带有张力,但当前所有标签都有值导致折线呈现锯齿状。想知道是否可以仅在进度变化的索引位置添加值,其余标签留空,让折线直接连接进度变化的点,或者有其他可行的解决方案?
解决方案
方法1:仅保留进度变化点数据,其余位置设为null
ChartJS会自动忽略null值,直接连接前后有有效数据的点,这样既能保留完整的日期标签,又能让折线自然连接进度变化节点,避免锯齿状。修改填充数据的脚本:
// 先初始化data数组,所有位置默认设为null chartData.datasets[0].data = new Array(chartData.labels.length).fill(null); const progressEntries = Object.entries(progress); progressEntries.forEach(([date, value]) => { // 找到该日期在labels数组中的索引 const index = chartData.labels.indexOf(date); if (index !== -1) { chartData.datasets[0].data[index] = value; } });
然后在ChartJS配置中开启折线张力:
const chart = new Chart(ctx, { type: 'line', data: chartData, options: { elements: { line: { tension: 0.4 // 可调整数值控制张力强度,0为无张力,0.3-0.5效果较自然 } } } });
方法2:直接用进度变化日期作为标签
如果不需要展示每日日期作为X轴标签,可以直接提取数据库中存储的进度变化日期作为标签,对应的值直接使用数据库中的进度值。这种方式更简洁,折线天然就是连接变化点的:
// 将进度数据按日期排序(注意转换日期格式以正确排序) const sortedProgress = Object.entries(progress) .sort(([aDate], [bDate]) => { const a = new Date(aDate.split('.').reverse().join('-')); const b = new Date(bDate.split('.').reverse().join('-')); return a - b; }); // 生成labels和data数组 chartData.labels = sortedProgress.map(([date]) => date); chartData.datasets[0].data = sortedProgress.map(([_, value]) => value);
同样在ChartJS配置中设置tension参数即可实现带张力的折线效果。
内容的提问来源于stack exchange,提问作者ICantCode
相关产品推荐
相关产品推荐

