You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于动态数据使用Morris.js绘制柱状图?

动态适配Morris柱状图的解决方案

1. 先理清核心问题:数据格式不匹配

你遇到的额外Undefined标签问题,本质是因为你的原始数据结构和Morris Bar要求的格式不兼容。Morris需要的data是每个元素对应一个x轴标签,包含该标签下所有系列的数值;而你的输入是每个元素对应一个数据系列,这就导致Morris错误解析了数据,生成了多余的x轴条目。

2. 编写动态数据转换函数

先把你的原始数据转换成Morris能识别的格式。假设你的原始数据是:

const rawData = [
  {"label":"Cats","values":[57,92,94]},
  {"label":"Dogs","values":[85,78,53]},
  {"label":"Birds","values":[81,57,70]}
];

我们写个函数把它转成Morris需要的结构:

function transformRawData(rawData) {
  // 先判断数据是否为空,避免报错
  if (!rawData.length || !rawData[0].values.length) return [];
  
  // 生成x轴标签(如果后端有提供明确的x轴名称,直接替换这里即可)
  const xLabels = rawData[0].values.map((_, idx) => `Period ${idx + 1}`);
  // 初始化转换后的数组,每个元素对应一个x轴标签
  const transformedData = xLabels.map(x => ({ x }));
  
  // 把每个系列的数值填充到对应的x轴条目里
  rawData.forEach(series => {
    // 把系列标签转成合法的对象key(处理空格/特殊字符)
    const seriesKey = series.label.toLowerCase().replace(/\s+/g, '_');
    series.values.forEach((value, idx) => {
      transformedData[idx][seriesKey] = value;
    });
  });
  
  return transformedData;
}

3. 动态生成系列配置项

有了转换后的数据,我们可以直接从原始数据里提取ykeys和labels,不管系列数量是2个还是N个都能适配:

// 生成ykeys:对应转换后data里的系列字段名
const ykeys = rawData.map(series => series.label.toLowerCase().replace(/\s+/g, '_'));
// 生成labels:图表上显示的系列名称
const labels = rawData.map(series => series.label);

4. 初始化动态图表

把这些动态生成的参数传入Morris.Bar,就能自动适配任意数量的系列了:

const transformedData = transformRawData(rawData);

Morris.Bar({
  element: 'bar-example',
  data: transformedData,
  xkey: 'x', // 对应转换后数据里的x轴字段
  ykeys: ykeys,
  labels: labels,
  resize: true, // 可选:窗口大小变化时自动重绘
  barColors: ['#0088cc', '#33bb55', '#ff6600'] // 可选:如果需要动态颜色,可以写个循环取色的逻辑
});

完整可运行示例

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.css">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/raphael/2.1.0/raphael-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/morris.js/0.5.1/morris.min.js"></script>
<div id="bar-example" style="height: 250px;"></div>

<script>
// 模拟从控制器获取的原始数据
const rawData = [
  {"label":"Cats","values":[57,92,94]},
  {"label":"Dogs","values":[85,78,53]},
  {"label":"Birds","values":[81,57,70]}
];

function transformRawData(rawData) {
  if (!rawData.length || !rawData[0].values.length) return [];
  
  // 这里可以替换成后端传递的真实x轴标签,比如年份、月份
  const xLabels = rawData[0].values.map((_, idx) => `Period ${idx + 1}`);
  const transformedData = xLabels.map(x => ({ x }));
  
  rawData.forEach(series => {
    const seriesKey = series.label.toLowerCase().replace(/\s+/g, '_');
    series.values.forEach((value, idx) => {
      transformedData[idx][seriesKey] = value;
    });
  });
  
  return transformedData;
}

const transformedData = transformRawData(rawData);
const ykeys = rawData.map(series => series.label.toLowerCase().replace(/\s+/g, '_'));
const labels = rawData.map(series => series.label);

// 动态生成颜色(可选)
const colorPool = ['#0088cc', '#33bb55', '#ff6600', '#9933cc', '#cc3333'];
const barColors = ykeys.map((_, idx) => colorPool[idx % colorPool.length]);

Morris.Bar({
  element: 'bar-example',
  data: transformedData,
  xkey: 'x',
  ykeys: ykeys,
  labels: labels,
  barColors: barColors,
  resize: true
});
</script>

额外优化提示

  • 如果后端能提供明确的x轴标签(比如["2021", "2022", "2023"]),直接替换xLabels的生成逻辑即可
  • 对于带空格或特殊字符的系列标签,用replace(/\s+/g, '_')转成合法的对象key,避免语法错误

内容的提问来源于stack exchange,提问作者diminuta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:23:07