首页 > 其他分享 >echarts动态排序柱状图

echarts动态排序柱状图

时间:2023-02-10 15:03:07浏览次数:48  
标签:function return option data value 柱状图 排序 数据 echarts

链接:https://juejin.cn/post/7149089840850534407
<!DOCTYPE html><html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>动态排序柱状图</title>
        <script src="js/echarts.js"></script>
        <script src="js/jquery_3.6.1.js"></script>
    </head>
    <body>
        <div id="main" style="width: 100%; height: 600px"></div>
        
        <script>
            var chartDom = document.getElementById('main');
            var myChart = echarts.init(chartDom);
            const updateFrequency = 2000;
            const countryColors = {
                Australia: "#00008b",
                Canada: "#f00",
                China: "#ffde00",
                Cuba: "#002a8f",
                Finland: "#003580",
                France: "#ed2939",
                Germany: "#000",
                Iceland: "#003897",
                India: "#f93",
                Japan: "#bc002d",
                "North Korea": "#024fa2",
                "South Korea": "#000",
                "New Zealand": "#00247d",
                Norway: "#ef2b2d",
                Poland: "#dc143c",
                Russia: "#d52b1e",
                Turkey: "#e30a17",
                "United Kingdom": "#00247d",
                "United States": "#b22234",
            };
            $.when(
                // 存在跨域问题
                // $.getJSON("https://fastly.jsdelivr.net/npm/[email protected]/data.json"),
                // $.getJSON("https://echarts.apache.org/examples/data/asset/data/life-expectancy-table.json")
                $.getJSON("./data/emoji-flags.json"),
                $.getJSON("./data/life-expectancy-table.json")
            ).done(function (res0, res1) {
                const flags = res0[0]; //flags是数组,数组中的每个元素是对象
                const data = res1[0]; //data也是数组,里面的每个元素还是数组
                const years = []; //存储data中的所有年份
                for (let i = 0; i < data.length; ++i) {
                    if (years.length === 0 || years[years.length - 1] !== data[i][4]) {
                        years.push(data[i][4]);
                    }
                }
                let startIndex = 10;
                let startYear = years[startIndex]; //从1890年开始
                //获取指定国家的emoji,也就是缩写
                function getFlag(countryName) {
                    if (!countryName) {
                        return "";
                    }
                    return (
                        flags.find(function (item) {
                            return item.name === countryName;
                        }) || {}
                    ).emoji;
                }
                option = {
                    //坐标系底板
                    grid: {
                        top: 10,
                        bottom: 30,
                        left: 150,
                        right: 80,
                    },
                    //x坐标轴
                    xAxis: {
                        max: "dataMax", //x坐标轴刻度最大值为数据的最大值
                        axisLabel: { //坐标轴刻度标签的相关设置
                            formatter: function (n) {
                                return Math.round(n) + ""; //刻度取整数
                            },
                        },
                    },
                    //初始数据集
                    dataset: {
                        source: data.slice(1).filter(function (d) {
                            return d[4] === startYear;
                        }),
                    },
                    //y坐标轴
                    yAxis: {
                        type: "category", //类目轴
                        inverse: true, //是否反向坐标轴
                        max: 10, //因为y是类目轴,所以这里指的是类目的序数,也就是只显示前11个类目
                        axisLabel: {
                            show: true,
                            fontSize: 14,
                            formatter: function (value) {
                                //原本标签值加上缩写,flag| 表示缩写采用rich中的flag定义的样式
                                return value + "{flag|" + getFlag(value) + "}";
                             },
                            rich: { //定义富文本样式
                                flag: {
                                    fontSize: 25,
                                    padding: 5,
                                },
                            },
                        },
                        animationDuration: 300,
                        animationDurationUpdate: 300,
                    },
                    //系列
                    series: [
                        {
                            realtimeSort: true, //是否开启该系列的实时排序
                            seriesLayoutBy: "column", //指定如何对应dataset中的数据
                            type: "bar", //柱状图
                            itemStyle: { //图形样式
                                color: function (param) { //柱条的颜色,param参数就是item对应的柱子
                                    return countryColors[param.value[3]] || "#5470c6";
                                },
                            },
                            encode: { //定义维度的编码(映射)
                                x: 0, //把第一个维度(输入)映射到x轴
                                y: 3, //把第四个维度(国家名称)映射到y轴
                            },
                            label: { //图形上的文本标签
                                show: true,
                                precision: 1, //标签的精度,表示保留一位小数
                                position: "right", //标签的位置
                                valueAnimation: true, //是否开启标签的数字动画
                                fontFamily: "monospace", //字体
                            },
                        },
                    ],
                    animationDuration: 0, //初始动画时长
                    animationDurationUpdate: updateFrequency, //数据更新动画的时长
                    // animationEasing: "linear", //初始动画缓动效果,因为没有初始动画,所以不需要写
                    animationEasingUpdate: "linear", //数据更新动画缓动效果
                    //原生图形元素组件,用来在图表中绘制一些形状
                    graphic: {
                        elements: [
                            {
                                type: "text", //图形种类
                                right: 160,
                                bottom: 60,
                                style: {
                                    text: startYear, //初始文本内容
                                    font: "bolder 80px monospace",
                                    fill: "rgba(100, 100, 100, 0.25)",
                                },
                                z: 100,
                            },
                        ],
                    },
                };
                myChart.setOption(option);
                for (let i = startIndex; i < years.length - 1; ++i) {
                    (function (i) {
                        //每隔updateFrequency更新一次数据,一开始立马更新一次
                        setTimeout(function () {
                            updateYear(years[i + 1]);
                        }, (i - startIndex) * updateFrequency);
                    })(i);
                }
                function updateYear(year) {
                    let source = data.slice(1).filter(function (d) {
                        return d[4] === year;
                    });
                    option.series[0].data = source; //更新系列中的数据
                    option.graphic.elements[0].style.text = year; //更新图表右下角的年份
                    myChart.setOption(option);
                }
            });
        </script>
    </body>
</html>

一、数据准备

$.when(
    $.getJSON("https://fastly.jsdelivr.net/npm/[email protected]/data.json"),
    $.getJSON("https://echarts.apache.org/examples/data/asset/data/life-expectancy-table.json"))
.done(function (res0, res1) {

$.when().done()是jQuery中的函数,意思是when中的成功执行后,执行done中的回调函数,done中回调函数的参数res0和res1分别是when中两个参数的返回值。

用VS Code 的 live server插件打开网页,执行这段代码会出现跨域问题而报错

我懒得研究怎么配置插件才能解决这个问题,干脆直接把数据下下来存在本地了。这两个json文件 emoji-flags.json 和 life-expectancy-table.json 中的数据分别为:
emoji-flags.json中是国家的缩写、全称等,如下:

life-expectancy-table.json中是19个国家在某个年份的人均收入、寿命、总人口数据,如下:

二、option设置

(一)xAxis 和 yAxis

1.max 坐标轴刻度最大值
可以设置成特殊值 'dataMax',此时取数据在该轴上的最大值作为最大刻度。
不设置时会自动计算最大值保证坐标轴刻度的均匀分布。
在类目轴中,也可以设置为类目的序数(如类目轴 data: ['类A', '类B', '类C'] 中,序数 2 表示 '类C'。也可以设置为负数,如 -3)。
当设置成 function 形式时,可以根据计算得出的数据最大最小值设定坐标轴的最小值。如:
max: function(value) {
return value.max - 20;
}
其中 value 是一个包含 min 和 max 的对象,分别表示数据的最大最小值,这个函数可返回坐标轴的最大值,也可返回 null/undefined 来表示“自动计算最大值”(返回 null/undefined 从 v4.8.0 开始支持)。
2.axisLabel 坐标轴刻度标签相关设置
(1)其中formatter用来设置刻度标签的内容格式器,支持字符串模板和回调函数两种形式。
官网中的例子是这样的:
// 使用字符串模板,模板变量为刻度默认标签 {value}
formatter: '{value} kg'
// 使用函数模板,函数参数分别为刻度数值(类目),刻度的索引
formatter: function(value, index) { return value + 'kg'; }
如果是时间轴的话,形式更多一些,详情可以看文档:时间轴的formatter用法
(2)rich用来定义富文本,和formatter搭配使用,用来给标签做出更丰富的效果。
在这个排序柱状图的例子中,它用来给y轴的刻度标签中的国家的缩写设置了特殊样式,可以看到国家全称的文字和缩写的文字是不一样的。

formatter: function (value) { //原本标签值加上缩写,flag| 表示缩写采用rich中的flag定义的样式
    return value + "{flag|" + getFlag(value) + "}";
 },
rich: { //定义富文本样式
    flag: {
        fontSize: 25,
        padding: 5,
    },
},

格式是 {styleName|text content},给text content采用rich中的styleName定义的样式。
实际中,富文本还会用在其他很多地方,用来增强描述。详情见文档:rich的详细用法
3.inverse 是否反向坐标轴
坐标轴默认是向右,向上是变大,将该属性设为true,则相应的坐标轴会反过来

(二)dataset 数据集

数据集(dataset)是专门用来管理数据的组件。虽然每个系列都可以在 series.data 中设置数据,但是从 ECharts4 支持 数据集 开始,更推荐使用 数据集 来管理数据。因为这样,数据可以被多个组件复用,也方便进行 “数据和其他配置分离“ 的配置风格。毕竟,在运行时,数据是最常改变的,而其他配置大多并不会改变。

dataset: {
    source: data.slice(1).filter(function (d) {
        return d[4] === startYear;
    }),
},

1.数组的slice方法:arr.slice([start[, end]])表示浅拷贝原数组中指定范围的元素到一个新数组中并返回。
2.数组的filter方法:通过回调函数设置的条件将原数组中符合条件的元素筛选出来放到一个新数组中并返回。
所以上面代码的意思就是将data中第一个元素(名称数组)去掉,再筛选出年份等于开始年份的所有元素作为数据集。

(三)series 系列

在 echarts 里,系列(series)是指:一组数值以及他们映射成的图。
1.realtimeSort 是否开启动态排序
这个属性虽然只需要简单的设置为true即可,但却非常重要。顾名思义,开启之后,echarts会自动动态的根据数据值进行排序,否则只有动态、没有排序
2.seriesLayoutBy 指定如何对应dataset中的数据
因为是通过dataset来设置数据,而不是在每个系列中直接用series.data设置数据,所以需要告诉echarts取dataset中每一行还是每一列的数据作为一个系列。这一行(列)称为一个维度(dimension),对应的列(行)称为一个数据项(item),这个概念在下面还会用到。
默认是column,可以设置为row。
在这个例子中dataset是一个数组,其中的每个元素依然是一个数组(拥有5个元素),所以dataset是一个n*5的二维数组:
                "Income", "Life Expectancy", "Population", "Country", "Year"
数据项1
数据项2

我们最终展示的是输入这一列,所以seriesLayoutBy属性设置为column。
此时每一列称为一个维度,输入这一列就是第一个维度,每一行就是一个数据项。
3.encode 定义维度的编码(映射)
文档中 echarts.apache.org/zh/option.h…
的解释是编码,当然这个词本身的意思就是编码,但是我感觉叫映射更好理解
encode 声明的基本结构如下,其中冒号左边是坐标系、标签等特定名称,如 'x', 'y', 'tooltip' 等,冒号右边是数据中的维度名(string 格式)或者维度的序号(number 格式,从 0 开始计数),可以指定一个或多个维度(使用数组)。
如果想使用维度名,则需要在dataset中用dimensions进行定义。
在这个例子中,意思是把第一个维度,也就是输入映射到x轴,把第4个维度,也就是国家名称映射到y轴

encode: { //定义维度的编码(映射)
    x: 0, //把第一个维度(输入)映射到x轴
    y: 3, //把第四个维度(国家名称)映射到y轴
},

4.itemStyle 设置图像样式

itemStyle: { //图形样式
    color: function (param) { //柱条的颜色,param参数就是item对应的柱子
        return countryColors[param.value[3]] || "#5470c6";
    },
},

回想上面第2条中item的含义,这里的意思就是设置柱形图中每一个柱子的颜色。
param是每个item对应的数据,param.value[3]就是item的数据中的第4项,也就是根据其国家名称在提前设置的颜色的的对象中找到对应的颜色,如果没找到则用#5470c6作为颜色。
5.label 图形上的文本标签
可用于说明图形的一些数据信息,比如值,名称等。
(1)valueAnimation 是否开启标签的数字动画
如果设为true,则数字的变动是连续的;如果设为false,则数字的变化是突变的,比如这次显示的是100,当下次数据来时直接变成200,没有从100逐渐涨到200的过程。
(2)precision 标签数字的精度
设置成几则表示显示几位小数

(四)动画相关

1.animationDuration 初始动画时长
就是从空白到显示初始值时的动画的时长,这个例子中设置为0,表示当你看到图形时初始值就已经显示在上面。
2.animationDurationUpdate 数据更新动画的时长
注意这个值要和设置的数据更新的间隔相同,否则看起来会有突变,不够丝滑。
这个例子中是定义了一个全局常量 updateFrequency 进行引用
3.animationEasing 初始动画缓动效果
动画效果这部分大家应该都很熟悉,css和jQuery中都接触过,关键字也都差不多。
4.animationEasingUpdate 数据更新动画缓动效果

(五)graphic 原生图形元素组件

用来在图表中绘制一些形状,支持的类型有:

标准写法是:

graphic: {
    elements: [
        {type: 'rect', ...},
        {type: 'circle', ...},
        ...
    ]
}

elements是所有图像元素的集合(数组),每个图形元素是一个对象。也可以直接省略elements,写成下面这种形式:

graphic: [
    {type: 'rect', ...},
    {type: 'circle', ...},
    ...
]

在这个例子中,通过graphic绘制的就是图表右下角的年份,如下图中的1980

三、数据更新

1.更新年份
function updateYear(year) {
let source = data.slice(1).filter(function (d) {
return d[4] === year;
});
option.series[0].data = source; //更新系列中的数据
option.graphic.elements[0].style.text = year; //更新图表右下角的年份
myChart.setOption(option);
}

2.设置定时执行

for (let i = startIndex; i < years.length - 1; ++i) {
    (function (i) {
        //每隔updateFrequency更新一次数据,一开始立马更新一次
        setTimeout(function () {
            updateYear(years[i + 1]);
        }, (i - startIndex) * updateFrequency);
    })(i);
}

( function ( i ) { } )表示定义一个匿名函数,该函数接收一个参数,
( function ( i ) { } )( i ) 表示调用这个匿名函数并传入参数 i
所以上面的代码就表示从起始索引开始,设置延时执行updateYear函数,延时时间等于更新时间乘以索引的差值。也就是每隔updateFrequency就更新一次数据。
值得注意的是上面的代码意味着,一开始就进行了一次更新,这就是为什么我们看到图表上的年份是从1900开始,而我们算出来startYear是1890。

总结:最关键的部分就是更新年份和设置定时执行。更新年份时,更新series中的data数据,graphic右边的年份字体,重新绘制图形。

自己找的简单版

还是有点小问题:Y轴的字体没出来

代码

<template>
  <div>
    <h1>出来吧</h1>
    <div id="main"></div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
export default {
  methods: {
    drawer() {
      var newArr = [
        {
          cdate: '2021-08',
          cname:
            '湖南省,江西省,湖北省,四川省,江苏省,广东省,河南省,甘肃省,贵州省,山东省,安徽省,广西壮族自治区,陕西省,福建省,河北省',
          cut: '79.10,13.82,1.28,0.56,0.49,0.48,0.47,0.47,0.41,0.32,0.30,0.29,0.24,0.24,0.22',
        },
        {
          cdate: '2021-09',
          cname:
            '湖南省,江西省,湖北省,广东省,河南省,四川省,广西壮族自治区,贵州省,福建省,陕西省,安徽省,江苏省,山东省,辽宁省,上海市',
          cut: '69.60,16.19,1.91,1.83,1.42,1.18,0.82,0.76,0.65,0.53,0.51,0.50,0.46,0.42,0.38',
        },
      ]
      const myChart = echarts.init(document.getElementById('main'))
      var updateFrequency = 6000
      var month = []
      var startIndex = 0
      for (var i = 0; i < newArr.length; ++i) {
        if (month.length == 0) {
          month.push(newArr[i])
        }
      }
      var startMonth = month[startIndex].cdate
      console.log(startMonth, 'startMonth')
      var startName = month[startIndex].cname.split(',')
      console.log(startName, 'startName')
      var startCut = month[startIndex].cut.split(',')
      console.log(startCut, 'startCut')
      var option = {
        grid: {
          top: 10,
          bottom: 30,
          left: 10,
          right: 30,
        },
        xAxis: {
          max: 'dataMax',
          //   x轴分割线
          splitLine: {
            show: true,
            lineStyle: {
              color: 'rgba(19,229,227, 0.4)',
              type: 'dashed',
            },
          },
        },
        // 数据集
        dataset: {
          source: newArr,
        },
        yAxis: {
          type: 'category',
          inverse: true,
          max: 15,
          data: startName,
          axisLabel: {
            show: true,
            textStyle: {
              fontSize: 14,
            },
            // 富文本
            rich: {
              flag: {
                fontSize: 25,
                padding: 5,
              },
            },
          },
          animationDuration: 300,
          animationDurationUpdate: 300,
        },
        series: [
          {
            realtimeSort: true, //开启动态
            seriesLayoutBy: 'column',
            type: 'bar',
            itemStyle: {
              color: 'rgb(13,208,229)',
            },
            encode: {
              x: 0, //指的是:cdata
              y: 3, //指的是:ccut,
            },
            // 柱状图右边的标签
            label: {
              show: true,
              precision: 1,
              position: 'right',
              valueAnimation: true,
              fontFamily: 'monospace',
              formatter: function (data) {
                return startCut[data.dataIndex] + '%'
              },
            },
            data: startCut,
          },
        ],
        animationDuration: 0, //初始动画的时长
        animationDurationUpdate: 1000, //更新动画的时长
        animationEasing: 'linear', //匀速
        animationEasingUpdate: 'linear', //匀速
        // 2019那个字体
        graphic: {
          elements: [
            {
              type: 'text',
              right: 30,
              bottom: 60,
              style: {
                text: startMonth,
                font: 'bolder 40px monospace',
                fill: 'rgba(19,229,227, 0.4)',
              },
              z: 100,
            },
          ],
        },
      }
      myChart.setOption(option)
      for (var i = startIndex; i < newArr.length - 1; ++i) {
        // 定时器
        ;(function (i) {
          setTimeout(function () {
            updateYear(newArr[i + 1])
          }, (i + 1) * updateFrequency)
        })(i)
      }
      //   调用方法,更新y轴排序,改变数的数据,改变水印位置,更新视图
      function updateYear(year) {
        option.yAxis.data = year.cname.split(',')
        option.series[0].data = year.cut.split(',')
        option.graphic.elements[0].style.text = year.cdate
        myChart.setOption(option)
      }
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.drawer()
    })
  },
}
</script>

<style lang="less" scoped>
#main {
  width: 500px;
  height: 500px;
  margin: 0 auto;
}
</style>

标签:function,return,option,data,value,柱状图,排序,数据,echarts
From: https://www.cnblogs.com/hxy--Tina/p/17108848.html

相关文章