10.9.1-Dataway+Echarts动态图表方案


整体 目标:

无代码或低代码,可以实现数据的图形化显示。

1. 技术选型

  • 图表:Apache ECharts。样例官网:https://echarts.apache.org/examples/zh/index.html
  • 后端接口数据:Hasor Dataway。官网:https://www.dataql.net/docs/dataway/overview

2. 实现方案

2.1. 方案介绍

**流程整合方案:**Dataway数据接口 + ECharts绘制Html = 动态图表

  • 工作流图:

  • 数据流图:

2.2. 方案实现(demo)

我们以一个日历图为例,来看一个动态图表实现的全过程。

  • 目标:在日历图上,显示有数据推送的日期,并根据推送的数据量多少,对日期色块以深浅进行区分。

  • 效果:

2.2.1. 使用echarts绘制html静态页

根据需求,从Apache ECharts样例官网:https://echarts.apache.org/examples/zh/index.html,筛选符合需求的图表。

2.2.1.1. 选择合适的图表

日历坐标系可以满足。

2.2.1.2. 下载html demo

下载样例,下载到的是一个完整可运行的html demo

<!--
	此示例下载自 https://echarts.apache.org/examples/zh/editor.html?c=calendar-simple
-->
<!DOCTYPE html>
<html lang="zh-CN" style="height: 100%">
<head>
  <meta charset="utf-8">
</head>
<body style="height: 100%; margin: 0">
  <div id="container" style="height: 100%"></div>

  
  <script type="text/javascript" src="https://fastly.jsdelivr.net/npm/echarts@5.4.1/dist/echarts.min.js"></script>

  <script type="text/javascript">
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });
    var app = {};
    
    var option;

    function getVirtualData(year) {
  const date = +echarts.time.parse(year + '-01-01');
  const end = +echarts.time.parse(year + '-12-31');
  const dayTime = 3600 * 24 * 1000;
  const data = [];
  for (let time = date; time <= end; time += dayTime) {
    data.push([
      echarts.time.format(time, '{yyyy}-{MM}-{dd}', false),
      Math.floor(Math.random() * 10000)
    ]);
  }
  return data;
}
option = {
  visualMap: {
    show: false,
    min: 0,
    max: 10000
  },
  calendar: {
    range: '2017'
  },
  series: {
    type: 'heatmap',
    coordinateSystem: 'calendar',
    data: getVirtualData('2017')
  }
};

    if (option && typeof option === 'object') {
      myChart.setOption(option);
    }

    window.addEventListener('resize', myChart.resize);
  </script>
</body>
</html>

至此,静态页面有了,我们需要的是一个动态数据接口,选择使用dataway开源项目来实现动态接口的创建。

dataway手册:https://www.dataql.net/docs/dataway/overview

需要的数据格式应该是:

[
  ['2022-11-16',9],
  ['2022-11-17',8],
  ['2022-12-03',66],
  ['2022-12-05',1014],
  ['2022-12-06',2253],
  ['2022-12-07',135]
]

2.2.2. 使用Dataway准备数据接口

2.2.2.1. 部署dataway

只需要在基础的springboot开箱代码基础上加上maven依赖及少量配置,即可run一个dataway服务。

  • dataway依赖表创建

    CREATE TABLE `interface_release` (
      `pub_id` varchar(64) NOT NULL COMMENT 'Publish ID',
      `pub_api_id` varchar(64) NOT NULL COMMENT '所属API ID',
      `pub_method` varchar(12) NOT NULL COMMENT 'HttpMethod:GET、PUT、POST',
      `pub_path` varchar(512) NOT NULL COMMENT '拦截路径',
      `pub_status` varchar(4) NOT NULL COMMENT '状态:-1-删除, 0-草稿,1-发布,2-有变更,3-禁用',
      `pub_comment` varchar(255) NOT NULL COMMENT '注释',
      `pub_type` varchar(24) NOT NULL COMMENT '脚本类型:SQL、DataQL',
      `pub_script` mediumtext NOT NULL COMMENT '查询脚本:xxxxxxx',
      `pub_script_ori` mediumtext NOT NULL COMMENT '原始查询脚本,仅当类型为SQL时不同',
      `pub_schema` mediumtext NOT NULL COMMENT '接口的请求/响应数据结构',
      `pub_sample` mediumtext NOT NULL COMMENT '请求/响应/请求头样本数据',
      `pub_option` mediumtext NOT NULL COMMENT '扩展配置信息',
      `pub_release_time` varchar(32) NOT NULL COMMENT '发布时间(下线不更新)',
      PRIMARY KEY (`pub_id`),
      KEY `idx_interface_release_api` (`pub_api_id`),
      KEY `idx_interface_release_path` (`pub_path`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='Dataway API 发布历史。';
    
    CREATE TABLE `interface_release` (
      `pub_id` varchar(64) NOT NULL COMMENT 'Publish ID',
      `pub_api_id` varchar(64) NOT NULL COMMENT '所属API ID',
      `pub_method` varchar(12) NOT NULL COMMENT 'HttpMethod:GET、PUT、POST',
      `pub_path` varchar(512) NOT NULL COMMENT '拦截路径',
      `pub_status` varchar(4) NOT NULL COMMENT '状态:-1-删除, 0-草稿,1-发布,2-有变更,3-禁用',
      `pub_comment` varchar(255) NOT NULL COMMENT '注释',
      `pub_type` varchar(24) NOT NULL COMMENT '脚本类型:SQL、DataQL',
      `pub_script` mediumtext NOT NULL COMMENT '查询脚本:xxxxxxx',
      `pub_script_ori` mediumtext NOT NULL COMMENT '原始查询脚本,仅当类型为SQL时不同',
      `pub_schema` mediumtext NOT NULL COMMENT '接口的请求/响应数据结构',
      `pub_sample` mediumtext NOT NULL COMMENT '请求/响应/请求头样本数据',
      `pub_option` mediumtext NOT NULL COMMENT '扩展配置信息',
      `pub_release_time` varchar(32) NOT NULL COMMENT '发布时间(下线不更新)',
      PRIMARY KEY (`pub_id`),
      KEY `idx_interface_release_api` (`pub_api_id`),
      KEY `idx_interface_release_path` (`pub_path`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='Dataway API 发布历史。';
    
  • dataway springboot项目引入相关依赖

    <!--hasor dataway-->
    <dependency>
        <groupId>net.hasor</groupId>
        <artifactId>hasor-spring</artifactId>
        <version>4.2.2</version>
    </dependency>
    <dependency>
        <groupId>net.hasor</groupId>
        <artifactId>hasor-dataway</artifactId>
        <version>4.2.2</version>
    </dependency>
    
    <!--作为 Spring Boot 项目有着自己完善的数据库方面工具支持。我们这次采用 druid + mysql + spring-boot-starter-jdbc 的方式。-->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.30</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.21</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.10</version>
    </dependency>
    
  • dataway springboot项目配置

    # 解决接口返回中文都是乱码
    server.servlet.encoding.charset=utf-8
    server.servlet.encoding.force=true
    server.servlet.encoding.enabled=true
    
    # 是否启用 Dataway 功能(必选:默认false)
    HASOR_DATAQL_DATAWAY=true
    # 是否开启 Dataway 后台管理界面(必选:默认false)
    HASOR_DATAQL_DATAWAY_ADMIN=true
    # dataway  API工作路径(可选,默认:/api/)
    HASOR_DATAQL_DATAWAY_API_URL=/api/
    # dataway-ui 的工作路径(可选,默认:/interface-ui/)
    HASOR_DATAQL_DATAWAY_UI_URL=/interface-ui/
    # SQL执行器方言设置(可选,建议设置)
    HASOR_DATAQL_FX_PAGE_DIALECT=mysql
    
    # db
    spring.datasource.url=jdbc:mysql://localhost:3306/cdc?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=Asia/Shanghai
    spring.datasource.username=root
    spring.datasource.password=123456
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
    # druid
    spring.datasource.druid.initial-size=3
    spring.datasource.druid.min-idle=3
    spring.datasource.druid.max-active=10
    spring.datasource.druid.max-wait=60000
    spring.datasource.druid.stat-view-servlet.login-username=admin
    spring.datasource.druid.stat-view-servlet.login-password=admin
    spring.datasource.druid.filter.stat.log-slow-sql=true
    spring.datasource.druid.filter.stat.slow-sql-millis=1
    
  • dataway springboot把数据源设置到 Hasor 容器中

    package com.example.simple;
    
    import net.hasor.core.ApiBinder;
    import net.hasor.core.DimModule;
    import net.hasor.db.JdbcModule;
    import net.hasor.db.Level;
    import net.hasor.spring.SpringModule;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import javax.sql.DataSource;
    
    @DimModule
    @Component
    public class ExampleModule implements SpringModule {
        @Autowired
        private DataSource dataSource = null;
    
        @Override
        public void loadModule(ApiBinder apiBinder) throws Throwable {
            // .DataSource form Spring boot into Hasor
            apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource));
        }
    }
    
  • 在 dataway springboot 中启用 Hasor

    package com.example.simple;
    
    import net.hasor.spring.boot.EnableHasor;
    import net.hasor.spring.boot.EnableHasorWeb;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @EnableHasor()
    @EnableHasorWeb()
    @SpringBootApplication
    public class SimpleApplication {
    
        public static void main(String[] args) {
            System.setProperty("file.encoding","UTF-8");
            SpringApplication.run(SimpleApplication.class, args);
        }
    
    }
    
    
  • 至此,即可启动应用

2.2.2.2. 创建数据接口

书接上回,我们需要的数据格式应该是:

[
  ['2022-11-16',9],
  ['2022-11-17',8],
  ['2022-12-03',66],
  ['2022-12-05',1014],
  ['2022-12-06',2253],
  ['2022-12-07',135]
]
  • sql编写

    对此,我们如果通过简单的sql,按天汇总数据量,那sql应该这么写:

    select DATE_FORMAT(add_time,'%Y-%m-%d') as time,sum(received_data_total) as sum 
    from cdc.`cdc_receive_round_log` where add_time > '2022-10-01' and data_platform='zgl' group by DATE_FORMAT(add_time,'%Y-%m-%d') ;
    

    在mysql中执行结果如下:

  • 基于sql,在dataway中创建接口

  • 验证接口是否可访问

    在浏览器访问: http://localhost:8080/api/received_count_per_day2

    可以拿到结果:

    {"success":true,"message":"OK","code":0,"lifeCycleTime":128,"executionTime":32,"value":{"zgl":[{"time":"2022-11-16","sum":9},{"time":"2022-11-17","sum":8},{"time":"2022-12-03","sum":66},{"time":"2022-12-05","sum":1014},{"time":"2022-12-06","sum":2253},{"time":"2022-12-07","sum":135}],"hsh":[{"time":"2022-10-08","sum":582},{"time":"2022-10-11","sum":165},{"time":"2022-10-14","sum":400},{"time":"2022-10-26","sum":200},{"time":"2022-11-03","sum":427},{"time":"2022-11-11","sum":200},{"time":"2022-11-18","sum":1500},{"time":"2022-11-30","sum":700},{"time":"2022-12-01","sum":882746},{"time":"2022-12-02","sum":260753}]}}
    

    上述如图:

but:

dataway接口返回的数据value.zgl内的报文,是一个list中嵌套dict。但是我们echarts需要的数据报文,是list里嵌套list。

我们要怎么将dataway的返参结果调整为echarts所需结构?

方案有二:

其一:通过dataway的dataql语法进行调整

其二:在echarts html中,拿到dataway接口数据报文后,通过js进行调整。

经过思考,毋庸置疑应选方案二,以减少学习成本。(下一节描述此案例如何调整。)

2.2.3. 调试html demo + dataway接口

直接看代码注释:

<!DOCTYPE html>
<html lang="zh-CN" style="height: 100%">

<head>
  <meta charset="utf-8">
</head>

<body style="height: 100%; margin: 0">
  <!-- 图表容器 -->
  <div id="container" style="height: 100%"></div>
  <!-- echarts js -->
  <script type="text/javascript" src="https://fastly.jsdelivr.net/npm/echarts@5.4.1/dist/echarts.min.js"></script>
  <!-- 由于需要异步加载数据,此处需要引入jquery -->
  <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.min.js"></script>

  <script type="text/javascript">
    // 获取dom,以便使用echarts进行渲染
    var dom = document.getElementById('container');
    var myChart = echarts.init(dom, null, {
      renderer: 'canvas',
      useDirtyRect: false
    });

    // 异步加载数据,http://localhost:8080/api/received_count_per_day2 就是我们使用dataway动态创建的接口
    $.get('http://localhost:8080/api/received_count_per_day2').done(function (data) {
      // zgl日历数据处理,将list嵌套dict,改为list嵌套list结构。
      var zgl_origion = data.value.zgl
      var zgl_echarts_data = []
      for (var i = 0; i < zgl_origion.length; i++) {
        var item = []
        item.push(zgl_origion[i]['time'])
        item.push(zgl_origion[i]['sum'])
        zgl_echarts_data.push(item)
      }
      //hsh日历数据处理,将list嵌套dict,改为list嵌套list结构。
      var hsh_origion = data.value.hsh
      var hsh_echarts_data = []
      for (var i = 0; i < hsh_origion.length; i++) {
        var item = []
        item.push(hsh_origion[i]['time'])
        item.push(hsh_origion[i]['sum'])
        hsh_echarts_data.push(item)
      }

      // 渲染图表
      myChart.setOption({
        title: {
          text: '' // 图表的头部文本
        },
        tooltip: {
          // 在划过日期块的时候,显示日期和数据。不写的话,默认只会显示数值,没有日期。
          formatter: function (p) {
            var format = echarts.format.formatTime('yyyy-MM-dd', p.data[0]);
            return format + '数量: ' + p.data[1];
          }
        },
        visualMap: {
          show: false,
          min: 0,
          max: 5000,
          textStyle: { color: '#000' },
          precision: 0,
          inRange: {
            // 在线调色板 https://www.sojson.com/web/panel.html
            // 色块深浅,将从下面的列表中根据数值大小自动选择
            color: ['#D4EFDF', '#82E0AA', '#58D68D', '#27AE60', '#229954', '#196F3D'],
            colorAlpha: 0.9, // 图元的颜色的透明度
          }
        },
        calendar: [{
          range: '2022',
          dayLabel: {
            show: true
          }
        },
        {
          top: 260,
          range: '2022',
          // cellSize: ['auto', 20]
        }
        ],
        series: [{
          type: 'heatmap',
          coordinateSystem: 'calendar',
          data: zgl_echarts_data // zgl数据渲染
        },
        {
          type: 'heatmap',
          coordinateSystem: 'calendar',
          calendarIndex: 1,
          data: hsh_echarts_data  // hsh数据渲染
        }]
      })
    });

    window.addEventListener('resize', myChart.resize);
  </script>
</body>

</html>

然后,直接用浏览器访问此页面,或在vscode中的live server进行访问:

可以看到,dataway是已经允许了跨域访问的,无需再做调整。

2.2.4. 发布html到nginx

2.2.4.1. 将完整url,放入到系统菜单上(配置菜单),使其可访问

这里要做的,是echarts html页面路径跟我们将要嵌入的系统域名保持一致,echarts html页面路径可以放在一个特别标记的位置上,比如 https://hello.com/my_echarts/calender_summary.html, 用诸如/my_echarts来让nginx区分是访问原系统页面或我们编写的echarts html页面即可。

同时,dataway接口已经支持跨域访问,不用调整不提。

3. 后期工作

  • 是否支持类似时间区间筛选之类的表头?

    理论上是支持的,因为echarts的图表,默认是放在一个html元素如div中,只需要进行简单的html编写

  • 图表的空间布局摆放要求?

    同上,记上css定位等html技术,即可实现静态页的调整。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值