求助:开发横轴以长度替代天数的类似日程图表(已试Syncfusion等库)
解决方案:自定义分段水平条形图(横轴替换为“长度”)
方案1:使用Chart.js实现
Chart.js支持堆叠水平条形图配置,完全可以适配你的需求,以下是可直接复用的核心代码:
数据结构定义
// 按项目分组,每个阶段对应长度值 const chartData = { labels: ["项目A", "项目B", "项目C"], datasets: [ { label: "阶段1", data: [120, 90, 150], backgroundColor: "#FF6384", borderColor: "#FF6384", borderWidth: 1 }, { label: "阶段2", data: [80, 110, 70], backgroundColor: "#36A2EB", borderColor: "#36A2EB", borderWidth: 1 }, { label: "阶段3", data: [50, 60, 80], backgroundColor: "#FFCE56", borderColor: "#FFCE56", borderWidth: 1 } ] };
图表配置(替换横轴为“长度”)
const config = { type: 'bar', data: chartData, options: { indexAxis: 'y', // 切换为水平条形图 scales: { x: { title: { display: true, text: '长度', // 替换原横轴的“天数” font: { size: 16, weight: 'bold' } }, stacked: true, // 开启堆叠模式 ticks: { precision: 0 } // 显示整数刻度 }, y: { stacked: true } }, plugins: { legend: { position: 'top' }, tooltip: { mode: 'index', intersect: false } } } }; // 初始化图表(需提前在页面添加<canvas id="myChart"></canvas>) new Chart(document.getElementById('myChart'), config);
方案2:原生Canvas手动绘制(高度自定义)
如果现有库的配置无法满足细节需求,原生Canvas可以实现100%自定义控制:
核心绘制代码
const canvas = document.getElementById('customChart'); const ctx = canvas.getContext('2d'); canvas.width = 800; canvas.height = 400; // 自定义数据 const projectData = [ { name: "项目A", stages: [120, 80, 50], colors: ["#FF6384", "#36A2EB", "#FFCE56"] }, { name: "项目B", stages: [90, 110, 60], colors: ["#FF6384", "#36A2EB", "#FFCE56"] }, { name: "项目C", stages: [150, 70, 80], colors: ["#FF6384", "#36A2EB", "#FFCE56"] } ]; const barHeight = 40; const padding = 60; // 计算最大总长度,用于刻度缩放 const maxTotalLength = projectData.reduce((max, item) => { return Math.max(max, item.stages.reduce((sum, len) => sum + len, 0)); }, 0); const scaleRatio = (canvas.width - padding * 2) / maxTotalLength; // 绘制横轴标签 ctx.font = '16px Arial'; ctx.fillText('长度', canvas.width / 2, canvas.height - 20); // 绘制每个项目的分段条形 projectData.forEach((item, idx) => { let currentX = padding; const yPos = padding + idx * (barHeight + 20); // 绘制项目名称 ctx.fillText(item.name, 10, yPos + barHeight / 2 + 5); // 绘制各阶段分段及长度标注 item.stages.forEach((length, stageIdx) => { ctx.fillStyle = item.colors[stageIdx]; ctx.fillRect(currentX, yPos, length * scaleRatio, barHeight); // 标注阶段长度 ctx.fillStyle = '#000'; ctx.fillText(length.toString(), currentX + 10, yPos + barHeight / 2 + 5); currentX += length * scaleRatio; }); }); // 绘制横轴刻度 for (let i = 0; i <= maxTotalLength; i += 50) { const tickX = padding + i * scaleRatio; ctx.beginPath(); ctx.moveTo(tickX, canvas.height - padding); ctx.lineTo(tickX, canvas.height - padding + 5); ctx.stroke(); ctx.fillText(i.toString(), tickX - 10, canvas.height - padding + 20); }
注意事项
- 你之前尝试的Syncfusion、Dhtmlx其实也支持这类需求,可能是未找到正确的堆叠条形图配置项,建议查阅官方文档中stacked bar chart+axis label customization的章节
- 原生Canvas方案适合需要特殊标注、自定义样式的场景,灵活性最高
内容的提问来源于stack exchange,提问作者Muhammad Hamza Khan
相关产品推荐
相关产品推荐

