当前位置: 首页>前端>正文

数据可视化插件echarts【前端】


数据可视化插件echarts【前端】

  • 前言
  • 版权
  • 开源
  • 推荐
  • 数据可视化插件echarts
  • 一、如何使用
  • 1.1 下载
  • 1.2 找到js文件
  • 1.3 入门使用
  • 1.4 我的使用
  • 二、前后端交互:入门demo
  • 2.1 前端
  • html
  • js
  • 2.2 后端
  • entity
  • controller
  • service
  • mapper
  • 三、前后端交互:动态数据
  • 3.1 前端
  • js
  • 3.2 后端
  • service
  • 四、前后端交互:动态数据
  • 4.1 前端
  • js
  • 4.2 后端
  • ChineseName注解
  • EldData
  • DataService
  • 五、测试扩展性
  • 5.0 开发说明
  • 5.1 测试结果
  • 5.2 Eld多加一个属性
  • 5.3 加入测试数据
  • 六、注解优化
  • 6.0 开发说明
  • 6.1 测试结果
  • 6.2 前端
  • 6.2 后端
  • ChineseName
  • EldData
  • DataService
  • 七、实际项目开发
  • EldData
  • Constant
  • 测试数据
  • 最后


前言

2024-4-12 16:08:09

开源

日星月云 / echarts数据可视化

v1:二、入门demo
v2:三、动态数据
v3:四、动态数据
v4:六、注解优化
v5:七、项目开发

推荐

echarts入门教程(超级详细带案例)

数据可视化插件echarts

一、如何使用

1.1 下载

(1)从 npm 获取
npm install echarts --save
(2)从 CDN 获取
(3)从 GitHub 获取

1.2 找到js文件

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_前端,第1张

node_modules\echarts\dist中找到
echart.jsecharts.min,js

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_echarts_02,第2张

1.3 入门使用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 01 导入js -->
		<script src="js/echarts.js"></script>
		<!-- 03 设置容器的样式 -->
		<style>
            #container{
                width: 800px;
                height: 600px;
            }
		</style>
	</head>
	<body>
		<!-- 02 创建个容器 -->
		<div id="container"></div>
	</body>
	<script>
        //04 实例化echarts
        // 4.1 创建一个实例
        var echart = echarts.init(document.getElementById("container"))
        // 4.2 定义配置项
        var option = {
            // 图表的标题
            title:{
                text:"我的第一个图表"
            },
            // 图表的提示
            tooltip:{},
            // 图例
            legend:{data:["睡眠时长"]},
            // x轴线
            xAxis:{data:["周一","周二","周三","周四","周五","周六","周日"]},
            // y轴线
            yAxis:{},
            // 设置数据
            series:[
                {
                    // 数据名称
                    name:"睡眠时长",
                    // 类型为柱状图
                    type:"bar",
                    // 数据data
                    data:[8,10,4,5,9,4,8]
                }
            ]
        }
        // 4.3 更新配置
        echart.setOption(option);
        // chart图表,set设置 Option选项  data数据 type类型 bar条(柱状条),series系列(数据) Axis轴线 xAxis水平轴线
        // legend传奇(图例) tooltip 提示 init初始化 document文档
	</script>

</html>

1.4 我的使用

下面的代码根据此代码修改

https://www.isqqw.com/?t=line

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_html_03,第3张

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<!-- 01 导入js -->
		<script src="js/echarts.js"></script>
		<!-- 03 设置容器的样式 -->
		<style>
            #container{
                width: 800px;
                height: 600px;
            }
		</style>
	</head>
	<body>
		<!-- 02 创建个容器 -->
		<div id="container"></div>
	</body>
	<script>
        //实例化echarts
        // 1 创建一个实例
        var echart = echarts.init(document.getElementById("container"));

        let data1 = [175, 160, 153, 121, 156]
        let data2 = [200, 140, 205, 162, 175]
        let data3 = []
        let data4 = ['13:00', '14:00', '15:00', '16:00', '17:00']
        data1.forEach((item1,index)=>{
            if(item1>data2[index]){
                data3.push(
                    {
                        yAxis: item1,  //标注的Y轴位置
                        xAxis: data4[index], //标注的X轴位置
                        value: item1  //标注的value值
                    }
                )
            }else{
                data3.push(
                    {
                        yAxis: data2[index],  //标注的Y轴位置
                        xAxis: data4[index], //标注的X轴位置
                        value: data2[index]  //标注的value值
                    }
                )
            }
        })

        // 2 定义配置项
        var option = {
            backgroundColor: 'white',
            grid: {
                top: '20%',
                left: '5%',
                right: '5%',
                bottom: '8%',
                containLabel: true
            },
            tooltip: {
                trigger: 'axis',
                borderWidth: 1,
                axisPointer: {
                    type: 'shadow'
                },
                extraCssText: 'z-index:2'

            },
            legend: [{
                top: 'top',
                left: 'center',
                orient: 'horizontal',
                data: ['进水量', '出水量'],
                itemWidth: 15,
                itemHeight: 10,
                itemGap: 15,
                borderRadius: 4,
                textStyle: {
                    color: '#000',
                    fontFamily: 'Alibaba PuHuiTi',
                    fontSize: 14,
                    fontWeight: 400
                }
            }],
            xAxis: {
                type: 'category',
                data: data4,
                axisLine: {
                    show: false
                },
                axisTick: {
                    show: false
                },
                axisLabel: {
                    show: true,
                    textStyle: {
                        color: '#393939' //X轴文字颜色
                    }
                }
            },
            yAxis: [

                {
                    type: 'value',
                    name: '',
                    nameTextStyle: {
                        color: '#000',
                        fontFamily: 'Alibaba PuHuiTi',
                        fontSize: 14,
                        fontWeight: 600
                        // padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离
                    },
                    nameGap: 30,  // 表现为上下位置
                    axisLine: {
                        show: true,
                        lineStyle: {
                            color: '#eeeeee'
                        }
                    },
                    axisTick: {
                        show: false
                    },
                    axisLabel: {
                        color: '#393939',
                        fontSize: 14
                    },
                    splitLine: {
                        show: true,
                        lineStyle: {
                            color: '#eeeeee'
                        }
                    }

                }

            ],
            series: [
                {
                    name: '进水量',
                    type: 'line',
                    showAllSymbol: true, //显示所有图形。
                    //标记的图形为实心圆
                    symbolSize: 8, //标记的大小
                    itemStyle: {
                        //折线拐点标志的样式
                        color: 'white',
                        borderWidth: '2',
                        borderColor: '#5470c6',
                        normal: {
                            color: '#5470c6'//拐点颜色
                        }
                    },
                    lineStyle: {
                        color: '#5470c6'
                    },
                    markPoint:{
                        data: data3
                    },
                    data: data1
                },
                {
                    name: '出水量',
                    type: 'line',
                    showAllSymbol: true, //显示所有图形。
                    symbolSize: 8, //标记的大小
                    itemStyle: {
                        //折线拐点标志的样式
                        color: 'white',
                        borderWidth: '2',
                        borderColor: '#91cc75',
                        normal: {
                            color: '#91cc75'//拐点颜色
                        }
                    },
                    lineStyle: {
                        color: '#91cc75'
                    },
                    data: data2
                }
            ]
        }
        // 3 更新配置
        echart.setOption(option);

	</script>

</html>

二、前后端交互:入门demo

2.1 前端

html
<div class="data-container">


		</div>
js
$(document).ready(function () {
   
    list();

});


function list() {
    $.ajax({
        type: "GET",
        url: SERVER_PATH + "/data/list",
        xhrFields: {withCredentials: true},
        success: function (result) {
            if (result.status) {
                alertBox(result.data.message);
                return false;
            }
            init(result.data);
        }
    });
}

function init(dataLists) {
    //实例化echarts
    // 1 创建一个实例
    var echart = echarts.init(document.querySelector(".data-container"));
    //进水量
    let data1 = dataLists.inWaterList;
    //出水量
    let data2 = dataLists.outWaterList;
    //标注
    let data3 = []
    //横轴时间
    let data4 = dataLists.dateList;
    data1.forEach((item1, index) => {
        if (item1 > data2[index]) {
            data3.push(
                {
                    yAxis: item1,  //标注的Y轴位置
                    xAxis: data4[index], //标注的X轴位置
                    value: item1  //标注的value值
                }
            )
        } else {
            data3.push(
                {
                    yAxis: data2[index],  //标注的Y轴位置
                    xAxis: data4[index], //标注的X轴位置
                    value: data2[index]  //标注的value值
                }
            )
        }
    })

    // 2 定义配置项
    var option = {
        backgroundColor: 'white',
        grid: {
            top: '20%',
            left: '5%',
            right: '5%',
            bottom: '8%',
            containLabel: true
        },
        tooltip: {
            trigger: 'axis',
            borderWidth: 1,
            axisPointer: {
                type: 'shadow'
            },
            extraCssText: 'z-index:2'

        },
        legend: [{
            top: 'top',
            left: 'center',
            orient: 'horizontal',
            data: ['进水量', '出水量'],
            itemWidth: 15,
            itemHeight: 10,
            itemGap: 15,
            borderRadius: 4,
            textStyle: {
                color: '#000',
                fontFamily: 'Alibaba PuHuiTi',
                fontSize: 14,
                fontWeight: 400
            }
        }],
        xAxis: {
            type: 'category',
            data: data4,
            axisLine: {
                show: false
            },
            axisTick: {
                show: false
            },
            axisLabel: {
                show: true,
                textStyle: {
                    color: '#393939' //X轴文字颜色
                }
            }
        },
        yAxis: [

            {
                type: 'value',
                name: '',
                nameTextStyle: {
                    color: '#000',
                    fontFamily: 'Alibaba PuHuiTi',
                    fontSize: 14,
                    fontWeight: 600
                    // padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离
                },
                nameGap: 30,  // 表现为上下位置
                axisLine: {
                    show: true,
                    lineStyle: {
                        color: '#eeeeee'
                    }
                },
                axisTick: {
                    show: false
                },
                axisLabel: {
                    color: '#393939',
                    fontSize: 14
                },
                splitLine: {
                    show: true,
                    lineStyle: {
                        color: '#eeeeee'
                    }
                }

            }

        ],
        series: [
            {
                name: '进水量',
                type: 'line',
                showAllSymbol: true, //显示所有图形。
                //标记的图形为实心圆
                symbolSize: 8, //标记的大小
                itemStyle: {
                    //折线拐点标志的样式
                    color: 'white',
                    borderWidth: '2',
                    borderColor: '#5470c6',
                    normal: {
                        color: '#5470c6'//拐点颜色
                    }
                },
                lineStyle: {
                    color: '#5470c6'
                },
                markPoint: {
                    data: data3
                },
                data: data1
            },
            {
                name: '出水量',
                type: 'line',
                showAllSymbol: true, //显示所有图形。
                symbolSize: 8, //标记的大小
                itemStyle: {
                    //折线拐点标志的样式
                    color: 'white',
                    borderWidth: '2',
                    borderColor: '#91cc75',
                    normal: {
                        color: '#91cc75'//拐点颜色
                    }
                },
                lineStyle: {
                    color: '#91cc75'
                },
                data: data2
            }
        ]
    }
    // 3 更新配置
    echart.setOption(option);

}

2.2 后端

entity
@lombok.Data
@NoArgsConstructor
@AllArgsConstructor
public class Data {
    Integer InWater;
    Integer OutWater;
    Date date;
}
controller
@GetMapping("/list")
    public ResponseModel getDataList(){
        HashMap<String, Object> search = dataService.searchMap();
        return new ResponseModel(search);
    }
service
public HashMap<String,Object> searchMap(){
        HashMap<String,Object> map=new HashMap<>();
        List<Data> dataList = search();
        List<Integer> inWaterList = new ArrayList<>();
        List<Integer> outWaterList = new ArrayList<>();
        List<Date> dateList = new ArrayList<>();

        for(Data data : dataList){
            inWaterList.add(data.getInWater());
            outWaterList.add(data.getOutWater());
            dateList.add(data.getDate());
        }

        map.put("inWaterList",inWaterList);
        map.put("outWaterList",outWaterList);
        map.put("dateList",dateList);

        return map;
    }

    public List<Data> search() {
        return dataDao.list();
    }
mapper
@Select("SELECT * FROM test limit 20")
    List<Data> list();

三、前后端交互:动态数据

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_前端_04,第4张

3.1 前端

js
$(document).ready(function () {
   
    list();

});


function list() {
    $.ajax({
        type: "GET",
        url: SERVER_PATH + "/data/list",
        data: {
            userId: 1
        },
        xhrFields: {withCredentials: true},
        success: function (result) {
            if (result.status) {
                alertBox(result.data.message);
                return false;
            }
            init(result.data);
        }
    });
}

function init(dataLists) {

    
    
    //实例化echarts
    // 1 创建一个实例
    var echart = echarts.init(document.querySelector(".data-container"));

    //进水量
    let data1 = dataLists.rate1;
    //出水量
    let data2 = dataLists.rate2;
    //横轴时间
    let data4 = dataLists.date;

    //标注数据
    let data3 = [];

    
    //只需修改以下对应
    let names=["rate1","rate2"];
    let datas=[data1,data2];
    let colors=[
        '#5470c6','#91cc75'
    ]

    //动态生成下面的数据
    for(let i=0;i<names.length;i++){
        data3.push([]);
    }

    datas.forEach((data, index) => {
        data.forEach((item, i) => {
            data3[index].push({
                yAxis: item,  // 标注的Y轴位置
                xAxis: data4[i], // 标注的X轴位置
                value: item  // 标注的value值
            });
        });
    
    });


    let seriesData=[];

    for (var i = 0; i < datas.length; i++) {
        seriesData.push({
            name: names[i],
            type: 'line',
            showAllSymbol: true, //显示所有图形。
            //标记的图形为实心圆
            symbolSize: 8, //标记的大小
            itemStyle: {
                //折线拐点标志的样式
                color: 'white',
                borderWidth: '2',
                borderColor: colors[i],
                normal: {
                    color: colors[i]//拐点颜色
                }
            },
            lineStyle:{
                color: colors[i]
            },
            markPoint: {
                data: data3[i]
            },
            data: datas[i]
        });
    }
    


    // 2 定义配置项
    var option = {
        backgroundColor: 'white',
        grid: {
            top: '20%',
            left: '5%',
            right: '5%',
            bottom: '8%',
            containLabel: true
        },
        tooltip: {
            trigger: 'axis',
            borderWidth: 1,
            axisPointer: {
                type: 'shadow'
            },
            extraCssText: 'z-index:2',
            // formatter: function(params) {
            //     var tooltipContent = params[0].name + '<br/>'; // 显示日期
            //     params.forEach(function(param) {
            //         tooltipContent += param.seriesName + ': ' + param.value + '<br>';
            //     });
            //     return tooltipContent;
            // }
        },
        legend: [{
            top: 'top',
            left: 'center',
            orient: 'horizontal',
            data: names,
            itemWidth: 15,
            itemHeight: 10,
            itemGap: 15,
            borderRadius: 4,
            textStyle: {
                color: '#000',
                fontFamily: 'Alibaba PuHuiTi',
                fontSize: 14,
                fontWeight: 400
            }
        }],
        xAxis: {
            type: 'category',
            data: data4,
            axisLine: {
                show: false
            },
            axisTick: {
                show: false
            },
            axisLabel: {
                show: true,
                textStyle: {
                    color: '#393939' //X轴文字颜色
                }
            }
        },
        yAxis: [

            {
                type: 'value',
                name: '',
                nameTextStyle: {
                    color: '#000',
                    fontFamily: 'Alibaba PuHuiTi',
                    fontSize: 14,
                    fontWeight: 600
                    // padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离
                },
                nameGap: 30,  // 表现为上下位置
                axisLine: {
                    show: true,
                    lineStyle: {
                        color: '#eeeeee'
                    }
                },
                axisTick: {
                    show: false
                },
                axisLabel: {
                    color: '#393939',
                    fontSize: 14
                },
                splitLine: {
                    show: true,
                    lineStyle: {
                        color: '#eeeeee'
                    }
                }

            }

        ],
        series: seriesData
    }
    // 3 更新配置
    echart.setOption(option);

}

3.2 后端

service
//返回数据链表
    public HashMap<String,ArrayList> searchMap(Integer userId){
        HashMap<String,ArrayList> map=new HashMap<>();
        List<EldData> dataList = search(userId);

        List<String> fieldNames = new ArrayList<>();
        Class<?> dataClass = EldData.class;

        // 获取 OldData 类的所有属性名
        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            fieldNames.add(field.getName());
            map.put(field.getName(),new ArrayList<>());
        }


        for (EldData data : dataList) {
            for (String fieldName : fieldNames) {
                ArrayList<Object> rowData =map.get(fieldName);
                try {
                    Field field = dataClass.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    rowData.add(field.get(data));
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
                map.put(fieldName,rowData);
            }

        }
        return map;
    }

    //搜索数据
    public List<EldData> search(Integer userId) {
        String key= ELD_DATA +userId;
        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, 19);// 获取分数最高的20个数据

        return set !=null?new ArrayList<>(set):new ArrayList<>();

    }

四、前后端交互:动态数据

后端name根据注解ChineseName
前端颜色是随机生成的

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_信息可视化_05,第5张

hashMap导致没有顺序,换成LinkedHashMap

在seachMap()中,重新定义

//        HashMap<String,ArrayList> map=new HashMap<>();
        HashMap<String,ArrayList> map=new LinkedHashMap<>();

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_echarts_06,第6张

发现它是时间顺序是反这的

修改一下

//搜索数据
//    public List<EldData> search(Integer userId) {
//        String key= ELD_DATA +userId;
//        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, limit-1);// 获取分数最高的20个数据
//
//        return set !=null?new ArrayList<>(set):new ArrayList<>();
//
//    }
    
    //搜索数据
    public List<EldData> search(Integer userId) {
        String key= ELD_DATA +userId;
        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, limit-1);// 获取分数最高的limit个数据
        if(set==null){
            return new ArrayList<>();
        }
        ArrayList<EldData> resList = new ArrayList<>(set);
        Collections.reverse(resList);
        return resList;

    }

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_数据可视化_07,第7张

4.1 前端

js

变成真实登录的用户
而不是固定userId是1

$(document).ready(function () {
   
    list();

});


function list() {

    var id=sessionStorage.getItem("id");

    $.ajax({
        type: "GET",
        url: SERVER_PATH + "/data/list",
        data: {
            // userId: 1
            userId: id
        },
        xhrFields: {withCredentials: true},
        success: function (result) {
            if (result.status) {
                alertBox(result.data.message);
                return false;
            }
            init(result.data);
        }
    });
}

function init(dataLists) {

    
    //实例化echarts
    // 1 创建一个实例
    var echart = echarts.init(document.querySelector(".data-container"));

    //横轴时间
    let datax = dataLists.date;
    //标注数据
    let data0 = [];

    
    //只需修改不需要展示的name
    var noNeed=["id","date"];

    //原始数据的所有name
    let keys=Object.keys(dataLists);

    //只需添加足够的颜色
    // let colors=[
    //     '#5470c6','#91cc75'
    // ]

    //动态生成下面的数据,不需要修改
    //随机生成相同数量的颜色
    let colors=generateRandomColors(keys.length);
    
   
    //名称和对应的数据
    let names = []
    let datas = [];

    keys.forEach((name) => {
        if(!noNeed.includes(name)){
            names.push(name);
            datas.push(dataLists[name]);
        }
        
    });

    
    for(let i=0;i<names.length;i++){
        data0.push([]);
    }

    datas.forEach((data, index) => {
        data.forEach((item, i) => {
            data0[index].push({
                yAxis: item,  // 标注的Y轴位置
                xAxis: datax[i], // 标注的X轴位置
                value: item  // 标注的value值
            });
        });
    
    });


    let seriesData=[];

    for (var i = 0; i < datas.length; i++) {
        seriesData.push({
            name: names[i],
            type: 'line',
            showAllSymbol: true, //显示所有图形。
            //标记的图形为实心圆
            symbolSize: 8, //标记的大小
            itemStyle: {
                //折线拐点标志的样式
                color: 'white',
                borderWidth: '2',
                borderColor: colors[i],
                normal: {
                    color: colors[i]//拐点颜色
                }
            },
            lineStyle:{
                color: colors[i]
            },
            markPoint: {
                data: data0[i]
            },
            data: datas[i]
        });
    }
    


    // 2 定义配置项
    var option = {
        backgroundColor: 'white',
        grid: {
            top: '20%',
            left: '5%',
            right: '5%',
            bottom: '8%',
            containLabel: true
        },
        tooltip: {
            trigger: 'axis',
            borderWidth: 1,
            axisPointer: {
                type: 'shadow'
            },
            extraCssText: 'z-index:2',
            // formatter: function(params) {
            //     var tooltipContent = params[0].name + '<br/>'; // 显示日期
            //     params.forEach(function(param) {
            //         tooltipContent += param.seriesName + ': ' + param.value + '<br>';
            //     });
            //     return tooltipContent;
            // }
        },
        legend: [{
            top: 'top',
            left: 'center',
            orient: 'horizontal',
            data: names,
            itemWidth: 15,
            itemHeight: 10,
            itemGap: 15,
            borderRadius: 4,
            textStyle: {
                color: '#000',
                fontFamily: 'Alibaba PuHuiTi',
                fontSize: 14,
                fontWeight: 400
            }
        }],
        xAxis: {
            type: 'category',
            data: datax,
            axisLine: {
                show: false
            },
            axisTick: {
                show: false
            },
            axisLabel: {
                show: true,
                textStyle: {
                    color: '#393939' //X轴文字颜色
                }
            }
        },
        yAxis: [

            {
                type: 'value',
                name: '',
                nameTextStyle: {
                    color: '#000',
                    fontFamily: 'Alibaba PuHuiTi',
                    fontSize: 14,
                    fontWeight: 600
                    // padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离
                },
                nameGap: 30,  // 表现为上下位置
                axisLine: {
                    show: true,
                    lineStyle: {
                        color: '#eeeeee'
                    }
                },
                axisTick: {
                    show: false
                },
                axisLabel: {
                    color: '#393939',
                    fontSize: 14
                },
                splitLine: {
                    show: true,
                    lineStyle: {
                        color: '#eeeeee'
                    }
                }

            }

        ],
        series: seriesData
    }
    // 3 更新配置
    echart.setOption(option);

}

function generateRandomColors(num) {
    let randomColors = [];
    let characters = '0123456789ABCDEF';
    
    for (let i = 0; i < num; i++) {
        let color = '#';
        for (let j = 0; j < 6; j++) {
            color += characters[Math.floor(Math.random() * 16)];
        }
        randomColors.push(color);
    }
    
    return randomColors;
}

4.2 后端

ChineseName注解
package com.jsss.echarts.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ChineseName {
    String value();
}
EldData
package com.jsss.echarts.entity;

import com.jsss.echarts.annotation.ChineseName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.sql.Date;
import java.util.Objects;


@Data
@NoArgsConstructor
@AllArgsConstructor

public class EldData {
    @ChineseName("id")
    String id;


    @ChineseName("率1")
    Integer rate1;

    @ChineseName("率2")
    Integer rate2;

    @ChineseName("date")
    Date date;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        EldData eldData = (EldData) o;
        return Objects.equals(id, eldData.id) && Objects.equals(date, eldData.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, date);
    }

    @Override
    public String toString() {
        return "EldData{" +
                "rate1=" + rate1 +
                ", rate2=" + rate2 +
                ", date=" + date +
                '}';
    }

}
DataService
package com.jsss.echarts.service;

import com.jsss.echarts.annotation.ChineseName;
import com.jsss.echarts.entity.EldData;
import com.jsss.utils.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.util.*;

@Service
public class DataService implements Constant {


    @Autowired
    RedisTemplate redisTemplate;


    //返回数据链表
    public HashMap<String,ArrayList> searchMap(Integer userId){
//        HashMap<String,ArrayList> map=new HashMap<>();
        HashMap<String,ArrayList> map=new LinkedHashMap<>();
        List<EldData> dataList = search(userId);

        List<String> fieldNames = new ArrayList<>();
        Class<?> dataClass = EldData.class;

        // 获取 OldData 类的所有属性名
        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
            fieldNames.add(field.getName());
//            map.put(field.getName(),new ArrayList<>());
            map.put(field.getAnnotation(ChineseName.class).value(), new ArrayList<>());
        }


        for (EldData data : dataList) {
            for (String fieldName : fieldNames) {
//                ArrayList<Object> rowData = map.get(fieldName);

                try {
                    Field field = dataClass.getDeclaredField(fieldName);
                    ArrayList<Object> rowData =map.get(field.getAnnotation(ChineseName.class).value());
                    field.setAccessible(true);
                    rowData.add(field.get(data));

                    map.put(field.getAnnotation(ChineseName.class).value(),rowData);
                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
//                map.put(fieldName, rowData);
            }

        }
        return map;
    }

    //搜索数据
//    public List<EldData> search(Integer userId) {
//        String key= ELD_DATA +userId;
//        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, 19);// 获取分数最高的20个数据
//
//        return set !=null?new ArrayList<>(set):new ArrayList<>();
//
//    }
    
    //搜索数据
    public List<EldData> search(Integer userId) {
        String key= ELD_DATA +userId;
        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, limit-1);// 获取分数最高的limit个数据
        if(set==null){
            return new ArrayList<>();
        }
        ArrayList<EldData> resList = new ArrayList<>(set);
        Collections.reverse(resList);
        return resList;

    }

    // 将数据存储到有序集合中,分数为日期的时间戳
    public boolean addData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().add(key, data,data.getDate().getTime());
    }

    // 更新数据,先删除数据,后增加新数据
    public boolean updateData(Integer userId,EldData oldData,EldData newData) {
        long res=removeData(userId,oldData);
        if (res==0){
            //没有旧数据,就修改失败
            return false;
        }
        return addData(userId, newData);
    }

    // 删除指定的数据
    public long removeData(Integer userId, EldData data) {
        String key= ELD_DATA +userId;
        return redisTemplate.opsForZSet().remove(key, data);
    }



}

五、测试扩展性

5.0 开发说明

后端:

只需要更改EldData的属性就好了
并且添加对应注解

如果有一个属性没有注解会报错,由于searchMap()中默认是所有属性都有此注解。

如果有属性不需要前端展示,可以在前端noNeed中添加
也可以后端修改注解,增加need属性,增加代码逻辑
另外:注解也可增加:x轴属性

@ChineseName("id")
    String id;

    @ChineseName("率1")
    Integer rate1;

    @ChineseName("率2")
    Integer rate2;

    @ChineseName("率3")
    Integer rate3;

    @ChineseName("date")
    Date date;

前端:

修改横轴:datax 怎么标注数据:data0 以及不需要展示的name链表:noNeed

//横轴时间
    let datax = dataLists.date;
    //标注数据
    let data0 = [];

    
    //只需修改不需要展示的name
    var noNeed=["id","date"];

5.1 测试结果

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_html_08,第8张

5.2 Eld多加一个属性

package com.jsss.echarts.entity;

import com.jsss.echarts.annotation.ChineseName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.sql.Date;
import java.util.Objects;


@Data
@NoArgsConstructor
@AllArgsConstructor

public class EldData {
    @ChineseName("id")
    String id;

    @ChineseName("率1")
    Integer rate1;

    @ChineseName("率2")
    Integer rate2;

    @ChineseName("率3")
    Integer rate3;

    @ChineseName("date")
    Date date;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        EldData eldData = (EldData) o;
        return Objects.equals(id, eldData.id) && Objects.equals(date, eldData.date);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, date);
    }


}

5.3 加入测试数据

@Autowired
    RedisTemplate redisTemplate;

    @Autowired
    DataService dataService;

    Integer userId=1;


    //清空数据
    @Test
    public void restore() {
        String key= ELD_DATA +userId;
        redisTemplate.delete(key);
        testSearchMap();

    }


    @Test
    public void testSearchMap(){
        HashMap<String, ArrayList> map = dataService.searchMap(userId);
        System.out.println(map);
    }

    @Test
    public void testValidAdd(){
        EldData eldData=new EldData(Toolbox.getRandomString(),175,160,111,new Date(2024-1900,4-1,8));
        dataService.addData(userId,eldData);
        eldData=new EldData(Toolbox.getRandomString(),160,140,121,new Date(2024-1900,4-1,9));
        dataService.addData(userId,eldData);
        eldData=new EldData(Toolbox.getRandomString(),153,205,131,new Date(2024-1900,4-1,10));
        dataService.addData(userId,eldData);
        eldData=new EldData(Toolbox.getRandomString(),121,162,141,new Date(2024-1900,4-1,11));
        dataService.addData(userId,eldData);
        eldData=new EldData(Toolbox.getRandomString(),156,175,151,new Date(2024-1900,4-1,12));
        dataService.addData(userId,eldData);

        testSearchMap();
    }

运行前端,登录admin:admin用户

在加入测试数据

userId=2

登录jsss:123456,也是可以的

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_html_09,第9张

2024-4-13 16:26:41

六、注解优化

6.0 开发说明

后端:
在EldData中

如果某个属性需要前端展示,就添加ChineseName注解
如果某个属性是横轴数据,其value值就是datax

前端:
不需要修改任何代码

public class EldData {


    @ChineseName("率1")
    Integer rate1;

    @ChineseName("率2")
    Integer rate2;

    //没有注解,就不展示
    Integer rate3;

    //横轴的注解的值是datax
    @ChineseName("datax")
    Date date;
    
}

6.1 测试结果

rate3没有注解

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_html_10,第10张

rate3添加注解

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_前端_11,第11张

6.2 前端

对应的改一下这两个就行了

//横轴数据
    let datax = dataLists.datax;

    //不需要展示的name
    var noNeed=["datax"];

6.2 后端

ChineseName
/**
 * 如果某个属性需要展示,就添加`ChineseName`注解 <br>
 * 如果某个属性是横轴数据,其`value`值是`datax` <br>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ChineseName {

    //中文name
    String value();

}
EldData

redis判断是根据序列化的结果判断是否相同,
equals和hashCode不起作用

package com.jsss.echarts.entity;

import com.jsss.echarts.annotation.ChineseName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.sql.Date;


@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class EldData {


    @ChineseName("率1")
    Integer rate1;

    @ChineseName("率2")
    Integer rate2;

    //没有注解,就不展示
    Integer rate3;

    //横轴的注解的值是datax
    @ChineseName("datax")
    Date date;
    
}
DataService
//返回数据链表
    public HashMap<String,ArrayList> searchMap(Integer userId){
        HashMap<String,ArrayList> map=new LinkedHashMap<>();
        List<EldData> dataList = search(userId);

        List<String> fieldNames = new ArrayList<>();
        Class<?> dataClass = EldData.class;

        // 获取 OldData 类的所有被ChineseName注解的属性名
        Field[] fields = dataClass.getDeclaredFields();
        for (Field field : fields) {
        	//添加是否有注解的判断
            ChineseName chineseNameAnnotation = field.getAnnotation(ChineseName.class);
            if (chineseNameAnnotation!=null){
                fieldNames.add(field.getName());
                map.put(field.getAnnotation(ChineseName.class).value(), new ArrayList<>());
            }
        }


        for (EldData data : dataList) {
            for (String fieldName : fieldNames) {
                try {
                    Field field = dataClass.getDeclaredField(fieldName);
                    field.setAccessible(true);
                    ArrayList<Object> rowData =map.get(field.getAnnotation(ChineseName.class).value());
                    rowData.add(field.get(data));

                    map.put(field.getAnnotation(ChineseName.class).value(),rowData);

                } catch (NoSuchFieldException | IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
        return map;
    }

    //搜索数据
    public List<EldData> search(Integer userId) {
        String key= ELD_DATA +userId;
        Set set = redisTemplate.opsForZSet().reverseRange(key, 0, limit-1);// 获取分数最高的limit个数据
        if(set==null){
            return new ArrayList<>();
        }
        ArrayList<EldData> resList = new ArrayList<>(set);
        Collections.reverse(resList);
        return resList;

    }

七、实际项目开发

加入分栏就更好了

数据可视化插件echarts【前端】,数据可视化插件echarts【前端】_echarts_12,第12张

EldData

package com.jsss.echarts.entity;

import com.jsss.echarts.annotation.ChineseName;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.sql.Date;

/**
 * 字段名称	类型	        字段说明	                    备注
 * <p>
 * HT	    Integer	    通用-身高(HT)	            单位:m
 * WT	    Integer	    通用-体重(WT)	            单位:kg
 * BMI	    Double	    通用-身高体重指数(BMI)	    正常范围 18.5~23.9,超重24.0~27.9,肥胖≥28.0
 * SBP	    Integer	    血压-收缩压(SBP)	            正常成年人的收缩压范围为90-140毫米汞柱(mmHg)。
 * DBP	    Integer	    血压-舒张压(DBP)	            正常成年人的舒张压范围为60-90毫米汞柱(mmHg)。
 * Hb	    Integer	    血常规-血红蛋白(Hb)	        正常成年人的正常范围为120-175克/升。
 * WBC	    Integer	    血常规-白细胞计数(WBC)	    正常成年人的白细胞计数范围为4-10 × 10^9/L。
 * PLT	    Integer	    血常规-血小板计数(PLT)	    正常成年人的血小板计数范围为100-300 × 10^9/L。
 * ALT	    Integer	    肝功能-谷丙转氨酶(ALT)	    正常成年人的ALT范围为10-40单位/升。
 * AST	    Integer	    肝功能-谷草转氨酶(AST)	    正常成年人的AST范围为10-35单位/升。
 * TBIL	    Double	    肝功能-总胆红素(TBIL)	        正常成年人的总胆红素范围为3.4-17.1毫摩尔/升。
 * BUN	    Double	    肾功能-血尿素氮(BUN)	        正常成年人的BUN范围为2.5-7.1毫摩尔/升。
 * Cr	    Integer	    肾功能-血肌酐(Cr)	        正常成年人的血肌酐范围为53-115微摩尔/升。
 * TC	    Double	    血脂-总胆固醇(TC)	        正常成年人的总胆固醇范围为3.1-5.2毫摩尔/升。
 * TG	    Double	    血脂-甘油三酯(TG)	        正常成年人的甘油三酯范围为0.4-1.7毫摩尔/升。
 * LDL_C	Double	    血脂-低密度脂蛋白胆固醇(LDL-C)	正常成年人的LDL-C范围为2.6-3.4毫摩尔/升。
 * FPG	    Double	    血糖-空腹血糖(FPG)	        正常成年人的空腹血糖范围为3.9-6.1毫摩尔/升。
 * twohPG	Double	    血糖-餐后2小时血糖(2hPG)	    正常成年人的餐后2小时血糖范围为3.9-7.8毫摩尔/升。
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class EldData {


    @ChineseName("通用-身高(米)")
    Integer HT;

    @ChineseName("通用-体重(千克)")
    Integer WT;

    @ChineseName("通用-身高体重指数(千克/米2)")
    Double BMI;

    @ChineseName("血压-收缩压(毫米汞柱)")
    Integer SBP;

    @ChineseName("血压-舒张压(毫米汞柱)")
    Integer DBP;

    @ChineseName("血常规-血红蛋白(克/升)")
    Integer Hb;

    @ChineseName("血常规-白细胞计数(10^9/升)")
    Integer WBC;

    @ChineseName("血常规-血小板计数(10^9/升)")
    Integer PLT;

    @ChineseName("肝功能-谷丙转氨酶(单位/升)")
    Integer ALT;

    @ChineseName("肝功能-谷草转氨酶(单位/升)")
    Integer AST;

    @ChineseName("肝功能-总胆红素(毫摩尔/升)")
    Double TBIL;

    @ChineseName("肾功能-血尿素氮(毫摩尔/升)")
    Double BUN;

    @ChineseName("肾功能-血肌酐(微摩尔/升)")
    Integer Cr;

    @ChineseName("血脂-总胆固醇(毫摩尔/升)")
    Double TC;

    @ChineseName("血脂-甘油三酯(毫摩尔/升)")
    Double TG;

    @ChineseName("血脂-低密度脂蛋白胆固醇(毫摩尔/升)")
    Double LDL_C;

    @ChineseName("血糖-空腹血糖(毫摩尔/升)")
    Double FPG;

    @ChineseName("血糖-餐后2小时血糖(毫摩尔/升)")
    Double twohPG;

    //横轴的注解的值是datax
    @ChineseName("datax")
    Date date;




}

Constant

package com.jsss.utils;

import com.jsss.echarts.entity.EldData;

import java.sql.Date;


public interface Constant {


    /**
     * redis键:老人的体检数据
     */
    String ELD_DATA = "eld_data:";

    EldData MIN_DATA=new EldData(
            Integer.MIN_VALUE,Integer.MIN_VALUE,18.5,
            90,60,
            120,4,100,
            10,10,3.4,
            2.5,53,
            3.1,0.4,2.6,
            63.9,7.8,
            new Date(System.currentTimeMillis())
            );

    EldData MAX_DATA=new EldData(
            Integer.MAX_VALUE,Integer.MAX_VALUE,23.9,
            140,90,
            175,10,300,
            40,35,17.1,
            7.1,115,
            5.2,1.7,2.4,
            6.1,7.8,
            new Date(System.currentTimeMillis())
    );


}

测试数据

package com.jsss.echarts;

import com.jsss.echarts.entity.EldData;
import com.jsss.echarts.service.DataService;
import com.jsss.utils.Constant;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.sql.Date;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

@SpringBootTest
public class EchartsTest implements Constant {

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    DataService dataService;

    Integer userId=1;

    Date date=new Date(2024-1900,4-1,14);

    @Test
    public void test(){
        System.out.println(date);
    }

    //清空数据
    @Test
    public void restore() {
        String key= ELD_DATA +userId;
        redisTemplate.delete(key);
        testSearchMap();

    }


    @Test
    public void testSearchMap(){
        HashMap<String, ArrayList> map = dataService.searchMap(userId);
        System.out.println(map);
    }



    @Test
    public void testValidAdd(){

        EldData eldData=randomData();
        eldData.setDate(new Date(2024-1900,4-1,8));
        dataService.addData(userId,eldData);
        eldData=randomData();
        eldData.setDate(new Date(2024-1900,4-1,9));
        dataService.addData(userId,eldData);
        eldData=randomData();
        eldData.setDate(new Date(2024-1900,4-1,10));
        dataService.addData(userId,eldData);
        eldData=randomData();
        eldData.setDate(new Date(2024-1900,4-1,11));
        dataService.addData(userId,eldData);
        eldData=randomData();
        eldData.setDate(new Date(2024-1900,4-1,12));
        dataService.addData(userId,eldData);

        testSearchMap();
    }

    EldData minData=MIN_DATA;
    EldData maxData=MAX_DATA;

    public EldData randomData(){
        EldData data=new EldData(
                randomInt(160,190), randomInt(45,80), randomDouble(minData.getBMI(),maxData.getBMI()),
                randomInt(minData.getSBP(),maxData.getSBP()),randomInt(minData.getDBP(),maxData.getDBP()),
                randomInt(minData.getHb(),maxData.getHb()),randomInt(minData.getWBC(),maxData.getWBC()),randomInt(minData.getPLT(),maxData.getPLT()),
                randomInt(minData.getALT(),maxData.getALT()),randomInt(minData.getAST(),maxData.getAST()),randomDouble(minData.getTBIL(),maxData.getTBIL()),
                randomDouble(minData.getBUN(),maxData.getBUN()),randomInt(minData.getCr(),maxData.getCr()),
                randomDouble(minData.getTC(),maxData.getTC()),randomDouble(minData.getTG(),maxData.getTG()),randomDouble(minData.getLDL_C(),maxData.getLDL_C()),
                randomDouble(minData.getFPG(),maxData.getFPG()),randomDouble(minData.getTwohPG(),maxData.getTwohPG()),
                new Date(System.currentTimeMillis())
        );

        return data;
    }

    public Integer randomInt(int min,int max){
        Random random = new Random();
        return random.nextInt(max - min + 1) + min; // 生成 min 到 max 范围内的随机 int 数
    }

    public Double randomDouble(double min,double max){
        Random random = new Random();
        return min + (max - min) * random.nextDouble(); // 生成 min 到 max 范围内的随机 double 值
    }


}

最后

2024-4-13 18:49:18

迎着日光月光星光,直面风霜雨霜雪霜。



https://www.xamrdz.com/web/22w1934900.html

相关文章: