后端加前端Echarts画图示例全流程(折线图,饼图,柱状图)

本文将带领读者通过一个完整的Echarts画图示例项目,演示如何结合后端技术(使用Spring Boot框架)和前端技术(使用Vue.js或React框架)来实现数据可视化。我们将实现折线图、饼图和柱状图三种常见的数据展示方式,通过具体的代码和步骤让读者掌握从零开始搭建项目到展示图表的全过程。

开发环境

后端

SpringBoot  2.6.13

Mybatis-Plus 3.4.3

前端

原生JavaScript

前期准备

数据库创建语句

CREATE TABLE sales_data (
    id INT AUTO_INCREMENT PRIMARY KEY,
    month VARCHAR(7) NOT NULL,
    amount DECIMAL(10, 2) NOT NULL
);

具体实现 

实体类

@Data
@TableName("sales_data")
public class SalesRecord {
    
    @TableId(type = IdType.AUTO)
    private Long id;
    
    private String month;
    
    private Double amount;
}

Mapper层

@Mapper
public interface SalesRecordMapper extends BaseMapper<SalesRecord> {
    // 自定义查询方法,根据月份范围查询销售记录
    @Select("SELECT * FROM sales_data WHERE month BETWEEN #{startMonth} AND #{endMonth}")
    List<SalesRecord> findByMonthBetween(@Param("startMonth") String startMonth, @Param("endMonth") String endMonth);
}

Service层

public interface SalesRecordService {
    List<SalesRecord> getAllSalesRecords();
    List<SalesRecord> getSalesRecordsByMonthRange(String startMonth, String endMonth);
}

Impl层

@Service
public class SalesRecordServiceImpl extends ServiceImpl<SalesRecordMapper, SalesRecord> implements SalesRecordService {

    @Resource
    private SalesRecordMapper salesRecordMapper;

    @Override
    public List<SalesRecord> getAllSalesRecords() {
        return list();
    }

    @Override
    public List<SalesRecord> getSalesRecordsByMonthRange(String startMonth, String endMonth) {
        // 实现根据月份范围查询的逻辑,使用 repository 或者自定义 SQL 查询数据库
        return salesRecordMapper.findByMonthBetween(startMonth, endMonth);
    }
}

Controller层

@RestController
@RequestMapping("/api/sales")
public class SalesRecordController {

    private final SalesRecordService salesRecordService;

    @Autowired
    public SalesRecordController(SalesRecordService salesRecordService) {
        this.salesRecordService = salesRecordService;
    }

    @GetMapping("/records")
    public List<SalesRecord> getAllSalesRecords() {
        return salesRecordService.getAllSalesRecords();
    }

    @GetMapping("/recordsByMonthRange")
    public List<SalesRecord> getSalesRecordsByMonthRange(
            @RequestParam("startMonth") String startMonth,
            @RequestParam("endMonth") String endMonth) {
        return salesRecordService.getSalesRecordsByMonthRange(startMonth, endMonth);
    }

}

前端页面

创建路径:src/main/resources/static/sales_bar_chart.html

柱形图(包含按照日期分页)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Sales Data Visualization</title>
  <!-- 引入 ECharts -->
  <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
  <!-- 引入 jQuery -->
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<!-- 时间范围选择表单 -->
<label for="startMonth">开始月份:</label>
<input type="month" id="startMonth" name="startMonth">
<label for="endMonth">结束月份:</label>
<input type="month" id="endMonth" name="endMonth">
<button onclick="updateChart()">更新图表</button>

<!-- 图表展示 -->
<div id="chart" style="width: 800px; height: 600px;"></div>

<script>
  // 初始化页面时渲染默认图表
  renderDefaultChart();

  // 渲染默认图表
  function renderDefaultChart() {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://localhost:8099/api/sales/records');
    xhr.onload = function () {
      if (xhr.status === 200) {
        var salesData = JSON.parse(xhr.responseText);
        renderChart(salesData);
      } else {
        console.error('Failed to fetch sales data:', xhr.statusText);
      }
    };
    xhr.onerror = function () {
      console.error('Request failed.');
    };
    xhr.send();
  }

  // 更新图表函数,根据用户选择的时间范围发送请求
  function updateChart() {
    var startMonth = document.getElementById('startMonth').value;
    var endMonth = document.getElementById('endMonth').value;

    var xhr = new XMLHttpRequest();
    xhr.open('GET', `http://localhost:8099/api/sales/recordsByMonthRange?startMonth=${startMonth}&endMonth=${endMonth}`);
    xhr.onload = function () {
      if (xhr.status === 200) {
        var salesData = JSON.parse(xhr.responseText);
        renderChart(salesData);
      } else {
        console.error('Failed to fetch sales data:', xhr.statusText);
      }
    };
    xhr.onerror = function () {
      console.error('Request failed.');
    };
    xhr.send();
  }

  // 渲染 ECharts 图表
  function renderChart(data) {
    var chart = echarts.init(document.getElementById('chart'));

    var months = data.map(function (item) {
      return item.month;
    });
    var amounts = data.map(function (item) {
      return item.amount;
    });

    var option = {
      title: {
        text: 'Monthly Sales Amount'
      },
      tooltip: {},
      xAxis: {
        data: months
      },
      yAxis: {},
      series: [{
        name: 'Sales Amount',
        type: 'bar',
        data: amounts
      }]
    };

    chart.setOption(option);
  }
</script>
</body>
</html>

 

饼图

创建路径:src/main/resources/static/pie-chart-ajax.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Sales Data Pie Chart</title>
  <!-- 引入 ECharts -->
  <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
</head>
<body>
<!-- 定义一个具有一定尺寸的 div,用于渲染图表 -->
<div id="pieChart" style="width: 600px; height: 400px;"></div>

<script>
  // 使用 AJAX 请求后端数据
  var xhr = new XMLHttpRequest();
  xhr.open('GET', 'http://localhost:8099/api/sales/records'); // 修改为实际的后端 API 路径
  xhr.onload = function () {
    if (xhr.status === 200) {
      var salesData = JSON.parse(xhr.responseText);
      renderPieChart(salesData);
    } else {
      console.error('Failed to fetch sales data:', xhr.statusText);
    }
  };
  xhr.onerror = function () {
    console.error('Request failed.');
  };
  xhr.send();

  // 渲染 ECharts 饼图
  function renderPieChart(data) {
    var pieChart = echarts.init(document.getElementById('pieChart'));

    // 构建饼图所需的数据格式
    var pieData = data.map(function(item) {
      return {
        name: item.month,
        value: item.amount
      };
    });

    // 配置饼图的选项
    var option = {
      title: {
        text: '销售数据分布'
      },
      tooltip: {
        trigger: 'item',
        formatter: '{a} <br/>{b} : {c} ({d}%)'
      },
      legend: {
        orient: 'vertical',
        left: 'left',
        data: data.map(function(item) { return item.month; }) // 设置图例数据
      },
      series: [
        {
          name: '销售数据',
          type: 'pie',
          radius: '55%',
          center: ['50%', '60%'],
          data: pieData // 使用从后端获取的数据
        }
      ]
    };

    // 使用配置项设置图表
    pieChart.setOption(option);
  }
</script>
</body>
</html>

折线图

创建路径:src/main/resources/static/sales_long_chart.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sales Data Line Chart</title>
    <!-- 引入 ECharts -->
    <script src="https://cdn.jsdelivr.net/npm/echarts/dist/echarts.min.js"></script>
    <!-- 引入 jQuery -->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
</head>
<body>
<!-- 定义一个具有一定尺寸的 div,用于渲染图表 -->
<div id="lineChart" style="width: 800px; height: 600px;"></div>

<script>
    // 使用 AJAX 请求后端数据
    var xhr = new XMLHttpRequest();
    xhr.open('GET', 'http://localhost:8099/api/sales/records'); // 修改为实际的后端 API 路径
    xhr.onload = function () {
        if (xhr.status === 200) {
            var salesData = JSON.parse(xhr.responseText);
            renderLineChart(salesData);
        } else {
            console.error('Failed to fetch sales data:', xhr.statusText);
        }
    };
    xhr.onerror = function () {
        console.error('Request failed.');
    };
    xhr.send();

    // 渲染 ECharts 折线图
    function renderLineChart(data) {
        var lineChart = echarts.init(document.getElementById('lineChart'));

        // 构建折线图所需的数据格式
        var xAxisData = data.map(function(item) {
            return item.month;
        });
        var seriesData = data.map(function(item) {
            return item.amount;
        });

        // 配置折线图的选项
        var option = {
            title: {
                text: '销售数据趋势'
            },
            tooltip: {
                trigger: 'axis',
                formatter: '{a} <br/>{b} : {c}'
            },
            xAxis: {
                type: 'category',
                data: xAxisData // 设置 X 轴数据
            },
            yAxis: {
                type: 'value'
            },
            series: [{
                name: '销售额',
                type: 'line',
                data: seriesData // 设置折线图数据
            }]
        };

        // 使用配置项设置图表
        lineChart.setOption(option);
    }
</script>
</body>
</html>

希望本文对你有所帮助。如果你有任何疑问或建议,欢迎在评论区留言讨论。Happy coding!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/767936.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【python】PyQt5事件机制、定时器原理分析和实战演练

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

哨兵1SAR空间数据包协议数据单元文档(五)

《哨兵1SAR空间数据包协议数据单元》文档对数据包的结构进行了详细描述&#xff0c;并提供了用户数据的格式和解码算法。 原文链接: 哨兵1SAR空间数据包协议数据单元文档英文版 同系列中的其他文章篇链接: 哨兵1SAR空间数据包协议数据单元文档&#xff08;一&#xff09; 哨兵1…

亚太万人eVTOL展!2024深圳eVTOL将于9月登陆鹏城

2024年以来&#xff0c;北京、上海等十多个省市&#xff0c;先后发布了鼓励低空经济发展的行动方案&#xff0c;其中&#xff0c;eVTOL&#xff08;电动垂直起降航空器&#xff09;成为低空经济最火热的细分赛道。2023年&#xff0c;中国eVTOL产业规模达9.8亿元&#xff0c;同比…

【C++】相机标定源码笔记- RGB 相机与 ToF 深度传感器校准类

类的设计目标是为了实现 RGB 相机与 ToF 深度传感器之间的高精度校准&#xff0c;从而使两种类型的数据能够在同一个坐标框架内被整合使用。这在很多场景下都是非常有用的&#xff0c;比如在3D重建、增强现实、机器人导航等应用中&#xff0c;能够提供更丰富的场景信息。 -----…

64位Office API声明语句第120讲

跟我学VBA&#xff0c;我这里专注VBA, 授人以渔。我98年开始&#xff0c;从源码接触VBA已经20余年了&#xff0c;随着年龄的增长&#xff0c;越来越觉得有必要把这项技能传递给需要这项技术的职场人员。希望职场和数据打交道的朋友&#xff0c;都来学习VBA,利用VBA,起码可以提高…

工厂模式之简单工厂模式

文章目录 工厂模式工厂模式分为工厂模式的角色简单工厂模式案例代码定义一个父类&#xff0c;三个子类定义简单工厂客户端使用输出结果 工厂模式 工厂模式属于创造型的模式&#xff0c;用于创建对象。 工厂模式分为 简单工厂模式&#xff1a;定义一个简单工厂类&#xff0c;根…

Vue3的模板语法插值表达式用法

在template中输入“5 3” &#xff0c;是没有运算能力的&#xff0c;只会把字符直接显示出来&#xff0c;代码如下&#xff1a; <template><view>这是demo</view><view>5 3</view><navigator open-type"navigateBack"><vi…

永劫无间国服延迟高、报错、卡顿的处理措施一览

永劫无间国服延迟高、报错、卡顿怎么办&#xff1f;快速解决办法分享 第一个办法&#xff1a;改善延迟 如果是一直遇到永劫无间国服延迟高、报错、卡顿的问题&#xff0c;重启游戏也不管用的话&#xff0c;那应该就是网络问题&#xff0c;玩家可以启动雷神&#xff0c;让其快速…

服了!DELETE 同一行记录也会造成死锁!!

1 问题背景 “哥们&#xff0c;又双叒叕写了个死锁&#xff0c;秀啊&#xff01;&#x1f60f;” 就算是经常写死锁的同学看到估计都会有点懵&#xff0c;两条一模一样的 DELETE 语句怎么会产生死锁呢&#xff1f; 2 MySQL 锁回顾 看到这里的靓仔肯定对 MySQL 的锁非常了解&…

红酒与建筑:品味历史与艺术的交汇

在时间的长河中&#xff0c;红酒与建筑都是人类智慧的结晶&#xff0c;它们各自承载着历史的厚重与艺术的韵味。当这两者交汇时&#xff0c;仿佛是一场穿越时空的对话&#xff0c;将我们带入一个既古老又现代、既深沉又温柔的世界。今天&#xff0c;就让我们一起走进这个奇妙的…

企业消费采购成本和员工体验如何实现“鱼和熊掌“的兼得?

有企业说企业消费采购成本和员工体验的关系好比是“鱼和熊掌”&#xff0c;无法兼得&#xff1f; 要想控制好成本就一定要加强管控&#xff0c;但是加强管控以后&#xff0c;就会很难让员工获得满意的体验度。如果不加以管控&#xff0c;员工自由度增加了&#xff0c;往往就很难…

为什么要在成像应用中使用图像采集卡?

达到最大产量是工业和工厂自动化的关键标准之一。提高传感器分辨率和帧速率有助于实现这一目标&#xff0c;但也使带宽达到极限&#xff0c;并提出了新的传输问题。当前高带宽接口(如10GigE、相机直接与PC连接和嵌入式系统)的实现促使成像应用的许多用户询问如何以最佳配置最优…

Day63 代码随想录打卡|回溯算法篇---电话号码的字母组合

题目&#xff08;leecode T17&#xff09;&#xff1a; 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 方法&#xff1a;…

CCS方形低角度光源实现更均匀的照射

机器视觉系统中&#xff0c;光源设计作为图像成像效果的关键&#xff0c;今天的光源系列分享——FPQ3系列。 特点&#xff1a; ・从4个方向以低角度照射均匀扩射光的方型低角度光源。 ・实现比上一代产品2倍的高输出。白色和蓝色的亮度提高至2倍&#xff0c;红色的亮度提高至…

app单页下载页源码带管理后台

新版带后台管理APP应用下载页,自动识别安卓苹果下载页&#xff0c;带管理后台&#xff0c;内置带3套App下载模板带中文模板/英文模板随时切换。 app单页下载页源码带管理后台

保存到redis中的token乱码了

示图&#xff1a; 原因是缓存保存到redis需要序列化操作&#xff0c;没有序列化会出现这样的问题 序列化redis第一步&#xff1a; package com.abliner.test.configure.redis;import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annota…

【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【17】认证服务01

持续学习&持续更新中… 守破离 【雷丰阳-谷粒商城 】【分布式高级篇-微服务架构篇】【17】认证服务01 环境搭建验证码倒计时短信服务邮件服务验证码短信形式&#xff1a;邮件形式&#xff1a; 异常机制MD5参考 环境搭建 C:\Windows\System32\drivers\etc\hosts 192.168.…

西南交通大学【算法分析与设计实验3】

实验3.3 任务分配问题 实验目的 &#xff08;1&#xff09;理解穷举法典型算法的求解过程。 &#xff08;2&#xff09;学习穷举法的时间复杂度分析方法&#xff0c;并通过实验验证算法的执行效率。 &#xff08;3&#xff09;学会如何利用穷举法求解具体问题&#xff0c;了…

51单片机嵌入式开发:STC89C52操作8八段式数码管原理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 STC89C52操作8八段式数码管原理 1 8位数码管介绍1.1 8位数码管概述1.2 8位数码管原理1.3 应用场景 2 原理图图解2.1 74HC573原理2.2 74HC138原理2.3 数码管原理 3 数码管程序…

现代智能宠物喂食器方案定制

现代智能宠物喂食器不仅具备定时喂食功能&#xff0c;帮助宠物主人管理宠物的饮食时间和食量&#xff0c;还加入了录音功能和摄像头&#xff0c;使得宠物主人即使不在家也能与宠物保持互动&#xff0c;并实时监控宠物的状况。此外&#xff0c;一些产品还具备紧急预警功能&#…