Echarts柱状图实现同时显示百分比+原始值+汇总值效果实例

 更新时间:2024年08月20日 10:47:13   作者:aimmon  
echarts是一款功能强大、灵活易用的数据可视化库,它提供了丰富的图表类型和样式,包括柱状图,这篇文章主要给大家介绍了关于Echarts柱状图实现同时显示百分比+原始值+汇总值效果的相关资料,需要的朋友可以参考下

原始效果:

柱状图:https://echarts.apache.org/examples/zh/editor.html?c=bar-stack-normalization

二开效果1:

核心逻辑

同时显示百分比和原始值

 label: {
      show: true,
      position: 'inside',
      formatter: (params) => {
        const rawValue = rawData[params.seriesIndex][params.dataIndex];
        const percentage = Math.round(params.value * 1000) / 10;
        return `${rawValue} \n(${percentage}%)`;
      }
    },

 显示汇总值

// Add a new series for displaying total values
series.push({
    name: 'Total',
    type: 'bar',
    stack: 'total',
    itemStyle: {
        color: 'rgba(0,0,0,0)' // 透明颜色
    },
    label: {
        show: true,
        position: 'top',
        formatter: params => `Total: ${totalData[params.dataIndex]}`
    },
    data: totalData.map(value => 0.01) // 微小的值以便能显示标签但不影响图形
});

代码解释

新增显示总值的系列

  • 您添加了一个名为 'Total' 的新系列到 series 数组中。
  • 这个系列使用 type: 'bar',并且堆叠在名为 'total' 的堆栈中,这与其他系列使用的堆栈名称一致。这确保了柱状图的对齐,即使该系列是不可见的。

透明的柱状图

  • itemStyle 被设置为 color: 'rgba(0,0,0,0)',使得该系列的柱状图完全透明。这是一个巧妙的方法,可以确保这些柱状图不增加任何可见的元素到图表中,但仍然可以在它们上面放置标签。

标签配置

  • label 对象中的 show: true 确保显示标签。
  • position 设置为 'top',因此标签显示在每个柱状图堆栈的顶部。
  • formatter 函数自定义了标签的文本。它使用 params.dataIndex 获取 totalData 中对应的值,并显示为 Total: {value}。这提供了关于每个类别(星期几)中所有堆叠元素的总值的清晰信息。

带有微小值的数据

  • 该系列的 data 数组被设置为 totalData.map(value => 0.01)。这将每个数据点设置为一个非常小的值(0.01)。这些微小的值的目的是为标签创建一个占位符,而不影响图表的实际可视化。由于柱状图本身是透明的,这个值确保了标签可以正确地定位和显示,而不会为柱状图增加任何视觉重量。

分析:

  • 使用透明的柱状图来显示标签:通过使用透明的柱状图,您可以在柱状图堆栈的顶部放置标签,而不会改变图表的视觉外观。这是一种常见的技术,当您希望添加额外的信息而不影响数据的可视化时。
  • 数据中的微小值:使用微小值(0.01)确保标签与柱状图相关联,但不会显著地影响堆叠柱状图的高度。这在ECharts中尤其有用,因为标签是与特定的数据点相关联的。
  • 堆叠配置:使用相同的堆叠标识符('total')使透明柱状图与其余堆叠柱状图完美对齐,确保标签位置的一致性。

这种方法对于突出显示总值,同时保持数据可视化的完整性非常有效。这是一个为图表提供额外信息而不使其变得混乱或扭曲的巧妙解决方案。

完整版代码

// There should not be negative values in rawData
const rawData = [
  [100, 302, 301, 334, 390, 330, 320],
  [320, 132, 101, 134, 90, 230, 210],
  [220, 182, 191, 234, 290, 330, 310],
  [150, 212, 201, 154, 190, 330, 410],
  [820, 832, 901, 934, 1290, 1330, 1320]
];
const totalData = [];
for (let i = 0; i < rawData[0].length; ++i) {
  let sum = 0;
  for (let j = 0; j < rawData.length; ++j) {
    sum += rawData[j][i];
  }
  totalData.push(sum);
}
const grid = {
  left: 100,
  right: 100,
  top: 50,
  bottom: 50
};
const series = [
  'Direct',
  'Mail Ad',
  'Affiliate Ad',
  'Video Ad',
  'Search Engine'
].map((name, sid) => {
  return {
    name,
    type: 'bar',
    stack: 'total',
    barWidth: '60%',
    label: {
      show: true,
      position: 'inside',
      formatter: (params) => {
        const rawValue = rawData[params.seriesIndex][params.dataIndex];
        const percentage = Math.round(params.value * 1000) / 10;
        return `${rawValue} \n(${percentage}%)`;
      }
    },
    data: rawData[sid].map((d, did) =>
      totalData[did] <= 0 ? 0 : d / totalData[did]
    )
  };
});
// Add a new series for displaying total values
series.push({
    name: 'Total',
    type: 'bar',
    stack: 'total',
    itemStyle: {
        color: 'rgba(0,0,0,0)' // 透明颜色
    },
    label: {
        show: true,
        position: 'top',
        formatter: params => `Total: ${totalData[params.dataIndex]}`
    },
    data: totalData.map(value => 0.01) // 微小的值以便能显示标签但不影响图形
});
option = {
  legend: {
    selectedMode: false
  },
  grid,
  yAxis: {
    type: 'value'
  },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  series
};

二开效果2:

完整版代码

// There should not be negative values in rawData
const rawData = [
  [100, 302, 301, 334, 390, 330, 320],
  [320, 132, 101, 134, 90, 230, 210],
  [220, 182, 191, 234, 290, 330, 310],
  [150, 212, 201, 154, 190, 330, 410],
  [820, 832, 901, 934, 1290, 1330, 1320]
];

const totalData = [];
for (let i = 0; i < rawData[0].length; ++i) {
  let sum = 0;
  for (let j = 0; j < rawData.length; ++j) {
    sum += rawData[j][i];
  }
  totalData.push(sum);
}

const grid = {
  left: 100,
  right: 100,
  top: 50,
  bottom: 50
};

const series = [
  'Direct',
  'Mail Ad',
  'Affiliate Ad',
  'Video Ad',
  'Search Engine'
].map((name, sid) => {
  return {
    name,
    type: 'bar',
    stack: 'total',
    barWidth: '60%',
    label: {
      show: true,
      position: 'inside', // Position the labels on top of the bars
      formatter: (params) => {
        const originalValue = rawData[sid][params.dataIndex];
        const percentage = (originalValue / totalData[params.dataIndex] * 100).toFixed(2);
        return `${originalValue} \n(${percentage}%)`;
      },
    },
    data: rawData[sid].map((d, did) =>
      totalData[did] <= 0 ? 0 : d / totalData[did]
    )
  };
});

option = {
  tooltip: {
    trigger: 'axis',
    axisPointer: {
      type: 'shadow'
    },
    formatter: (params) => {
      const total = totalData[params[0].dataIndex];
      const header = `<div style="font-weight:bold">${params[0].axisValue}</div>
                      <div>Total: ${total}</div>`;
      const body = params.map(param => {
        const originalValue = rawData[param.seriesIndex][param.dataIndex];
        const percentage = (originalValue / total * 100).toFixed(2);
        return `<div>${param.seriesName}: ${originalValue} (${percentage}%)</div>`;
      }).join('');
      return header + body;
    }
  },
  legend: {
    selectedMode: false
  },
  grid,
  yAxis: {
    type: 'value'
  },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  series
};

实现思路与修改:

计算每天的总访问数:首先遍历 rawData 并计算每一天所有来源的总访问数。这些总数被存储在 totalData 数组中。

配置每个数据源系列:为每一个数据源创建一个 series 对象。每个系列代表一种访问来源,并包含一些配置选项,如类型、堆叠设置、标签显示方式等。

配置标签显示:为了让用户在图表上直观地看到原始值和占比,我们需要在每个柱形上添加标签。标签的内容包括原始值和百分比。

配置提示框(Tooltip):为了提供更丰富的信息,我们配置了一个提示框,当用户悬停在柱形上时会显示当天的总访问数和各个来源的具体数值及占比。

二开效果3:

完整版代码

// There should not be negative values in rawData
const rawData = [
  [100, 302, 301, 334, 390, 330, 320],
  [320, 132, 101, 134, 90, 230, 210],
  [220, 182, 191, 234, 290, 330, 310],
  [150, 212, 201, 154, 190, 330, 410],
  [820, 832, 901, 934, 1290, 1330, 1320]
];

const totalData = [];
for (let i = 0; i < rawData[0].length; ++i) {
  let sum = 0;
  for (let j = 0; j < rawData.length; ++j) {
    sum += rawData[j][i];
  }
  totalData.push(sum);
}

const grid = {
  left: 100,
  right: 100,
  top: 50,
  bottom: 50
};

const series = [
  'Direct',
  'Mail Ad',
  'Affiliate Ad',
  'Video Ad',
  'Search Engine'
].map((name, sid) => {
  return {
    name,
    type: 'bar',
    stack: 'total',
    barWidth: '60%',
    label: {
      show: true,
      position: 'inside', // Position the labels on top of the bars
      formatter: (params) => {
        const originalValue = rawData[sid][params.dataIndex];
        const percentage = (originalValue / totalData[params.dataIndex] * 100).toFixed(2);
        return `${originalValue} (${percentage}%)`;
      },
    },
    itemStyle: {
      emphasis: {
        // focus : 'series',
        label: {
          show: true,
          position: 'top',
          fontSize: 12,
          color: 'red',
          formatter: (params) => totalData[params.dataIndex]
        }
      }
    },
    data: rawData[sid].map((d, did) =>
      totalData[did] <= 0 ? 0 : d / totalData[did]
    )
  };
});

option = {
  legend: {
    selectedMode: false
  },
  grid,
  yAxis: {
    type: 'value'
  },
  xAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  series
};

解释:

  • 添加了 itemStyle 选项,其中包含了 emphasis 子项。
  • 在 emphasis 中设置了 label,用于在鼠标悬停时显示总值。
  • emphasis.label.show 设为 true,表示在鼠标悬停时显示标签。
  • emphasis.label.position 设为 'bottom',使标签显示在柱子底部。
  • emphasis.label.fontSize 设为 12,调整字体大小。
  • emphasis.label.formatter 使用 totalData[params.dataIndex] 显示当前柱子对应的总值

柱状图转换为条形图

核心代码修改,变更xAxis,yAxis 中的 x y 即可

 条形图同时展示百分比、原始值、汇总值功能

// There should not be negative values in rawData
const rawData = [
  [100, 302, 301, 334, 390, 330, 320],
  [320, 132, 101, 134, 90, 230, 210],
  [220, 182, 191, 234, 290, 330, 310],
  [150, 212, 201, 154, 190, 330, 410],
  [820, 832, 901, 934, 1290, 1330, 1320]
];
const totalData = [];
for (let i = 0; i < rawData[0].length; ++i) {
  let sum = 0;
  for (let j = 0; j < rawData.length; ++j) {
    sum += rawData[j][i];
  }
  totalData.push(sum);
}
const grid = {
  left: 100,
  right: 100,
  top: 50,
  bottom: 50
};
const series = [
  'Direct',
  'Mail Ad',
  'Affiliate Ad',
  'Video Ad',
  'Search Engine'
].map((name, sid) => {
  return {
    name,
    type: 'bar',
    stack: 'total',
    barWidth: '60%',
    label: {
      show: true,
       position: 'inside',
      formatter: (params) => {
        const rawValue = rawData[params.seriesIndex][params.dataIndex];
        const percentage = Math.round(params.value * 1000) / 10;
        return `${rawValue} \n(${percentage}%)`;
      }

    },
    data: rawData[sid].map((d, did) =>
      totalData[did] <= 0 ? 0 : d / totalData[did]
    )
  };
});
series.push({
    name: 'Total',
    type: 'bar',
    stack: 'total',
    itemStyle: {
        color: 'red' // 透明颜色
    },
    label: {
        show: true,
        // position: 'middle',
        formatter: params => `Total: ${totalData[params.dataIndex]}`
    },
    data: totalData.map(value => 0.0) // 微小的值以便能显示标签但不影响图形
});
option = {
  legend: {
    selectedMode: false
  },
  grid,
  xAxis: {
    type: 'value'
  },
  yAxis: {
    type: 'category',
    data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
  },
  series
};

效果展示

总结 

到此这篇关于Echarts柱状图实现同时显示百分比+原始值+汇总值效果的文章就介绍到这了,更多相关Echarts柱状图同时显示百分比原始值内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Ajax与Axios的基础知识以及详细对比总结

    Ajax与Axios的基础知识以及详细对比总结

    在Web开发中Ajax和Axios是两种实现异步数据请求的技术,Ajax可以在不刷新页面的情况下与服务器通信,Axios是一个基于Promise的HTTP客户端,简化了HTTP请求的过程,两者都能处理多种数据格式,这篇文章主要介绍了Ajax与Axios的基础知识以及详细对比总结,需要的朋友可以参考下
    2024-09-09
  • 微信小程序之swiper滑动面板用法示例

    微信小程序之swiper滑动面板用法示例

    这篇文章主要介绍了微信小程序之swiper滑动面板用法,结合实例形式详细分析了swiper滑动面板的具体功能、参数、使用方法及相关操作注意事项,需要的朋友可以参考下
    2018-12-12
  • Javascript操作cookie的函数代码

    Javascript操作cookie的函数代码

    之前发布了javascript操作cookie一个大全里面有很多知识,大家可以在本站搜索,另外今天遇到js操作cookie又增加2款方法一个是简单版本、一个是封装版本,特意分享给大家
    2012-10-10
  • Object.keys()的用法示例详解

    Object.keys()的用法示例详解

    Object.keys()是遍历一个对象自身的属性名称(不包括继承属性)的最简单方法,这篇文章主要介绍了Object.keys()的用法,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07
  • JS实现左边列表移到到右边列表功能

    JS实现左边列表移到到右边列表功能

    这篇文章主要介绍了JS实现左边列表移到到右边列表功能,实现功能主要是左边的下拉框内容添加到右边的下拉框,支持多选移动,且同时将右边的下拉框对象移除,需要的朋友可以参考下
    2018-03-03
  • JavaScript上传文件时不用刷新页面方法总结(推荐)

    JavaScript上传文件时不用刷新页面方法总结(推荐)

    这篇文章主要介绍了JavaScript上传文件时不用刷新页面方法,用js+css代码详细介绍了操作过程,需要的朋友可以参考下
    2017-08-08
  • 基于javascript实现按圆形排列DIV元素(二)

    基于javascript实现按圆形排列DIV元素(二)

    本篇文章主要介绍基于javascript实现按圆形排列DIV元素的方法,此文着重于介绍怎样实现的按圆形排列DIV元素的运动原理和实现效果代码,需要的朋友来看下吧
    2016-12-12
  • 深入浅出聊一聊js中的'this'关键字

    深入浅出聊一聊js中的'this'关键字

    js中的this关键字平时在开发中使用时倒是也能正常应用,但是对其使用和判断并不能信手拈来,所以下面这篇文章主要给大家介绍了关于js中this关键字的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • 微信小程序实现手势解锁的示例详解

    微信小程序实现手势解锁的示例详解

    手势解锁是生活中常用的解锁方式,本文将通过微信小程序实现手势解锁这一功能,本实例以工具的形式可以嵌入到不同的项目之中,感兴趣的可以了解一下
    2022-04-04
  • jsp 自动编译机制详细介绍

    jsp 自动编译机制详细介绍

    这篇文章主要介绍了 Jasper的自动检测实现的机制比较简单,依靠某后台线程不断检测JSP文件与编译后的class文件的最后修改时间是否相同,若相同则认为没有改动,但倘若不同则需要重新编译,需要的朋友可以参考下
    2016-12-12

最新评论