📊 搭建基于 Cube.js 的 Vue Dashboard

Cube.js

Cube.js - 一个完整的开源数据分析解决方案:提供高性能的大规模数据集分析技术基础架构,同时提供前端友好的API,用于构建仪表盘报表以及其他数据分析应用,它扮演了前端与后端之间的数据层角色。

Cube.js 客户端执行查询,Cube.js 后端将业务逻辑(dimensions 和 measures 以及 filters)通过 Cube.js Schema 转换为SQL语句并交由数据库执行,业务逻辑的设计这一点很契合我的开源图表库 ve-charts数据设计理念。

ve-charts 的数据设计采用数据分析的基础概念,用维度和度量的组合提供可视化和数据。ve-charts 接收的数据格式为 JSON 对象,分为 dimensions 维度与 measures 度量。

什么是维度与度量?

  • 维度

维度确定如何对可视化内容数据分组,通常呈现在条形图的 X 轴上或饼图的切片上,例如时间、区域、产品类型等。

  • 度量

度量是在可视化中使用的计算,结果为具体的参考数值,通常呈现在条形图的 Y 轴上或表格的列中。度量通过由聚合函数(例如 Sum 或 Max)组成的与一个或多个字段组合的表达式创建,例如蒸发量、降水量、销售额等。

Vue Dashboard

接下来我们用 Vue, Cube.jsve-charts 来构建一个 Dashboard 应用,这里查看 Demo,或者查看下方示例

构建 Dashboard 需要使用 Cube.js 的两个客户端库:

  • @cubejs-client/core 根据后端服务URL以及 API Token 创建 Cube.js 实例
  • @cubejs-client/vue 基于 Vue 组件的客户端API
// Dashboard.vue
import cubejs from "@cubejs-client/core";
import { QueryBuilder } from "@cubejs-client/vue";
    
const cubejsApi = cubejs(
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.K9PiJkjegbhnw4Ca5pPlkTmZihoOm42w8bja9Qs2qJg",
  { apiUrl: "https://react-query-builder.herokuapp.com/cubejs-api/v1" }
);

QueryBuilder API 用于构建交互式分析查询构建器。 它抽象了 Cube.js Backend 的状态管理和API调用。借助于 Vue 中的作用域插槽(Scoped Slot Props )特性,将数据处理结果作为 props 传输到图表适配器(ChartAdapter)组件内部。

// Dashboard.vue
<!-- New Users Over Time Query -->
<query-builder :cubejs-api="cubejsApi" :query="lineQuery">
  <template v-slot="{ loading, resultSet }">
        <!-- 图表适配器组件 -->
    <chart-adapter v-if="!loading" type="line" :result-set="resultSet"/>
  </template>
</query-builder>

图表适配器组件

渲染不同类型图表

// ChartAdapter.vue
<template>
  <div class="cube-chart-adpater">
    <!-- 渲染统计数值 -->
    <statistic v-if="type === 'stat'" :title="title" :value="statValue" />
    <!-- 渲染折线图 -->
    <ve-line-chart v-if="type === 'line'" :data="chartData" :settings="lineSettings" />
    <!-- 渲染柱状图 -->    
    <ve-bar-chart v-if="type === 'bar'" :data="chartData" :settings="barSettings" />
  </div>
</template>

数据映射

根据客户端 ResultSet API,处理数据,映射为图表库数据格式。

// ChartAdapter.vue
export default {
    ...
  computed: {
    // 系列名称
    seriesNames () {
      return this.resultSet.seriesNames()
    },
    // 度量
    metrics () {
      if (this.loading) return [''];
      return this.seriesNames.map(x => x.key);
    },
    // 规范化的查询结果
    chartPivot () {
      if (this.loading) return [];
      return this.resultSet.chartPivot();
    },
    // 统计指标数值
    statValue () {
      return parseFloat(this.chartPivot[0][this.metrics[0]])
    }
  },
  mounted () {
    let dimensionsData = []
    const measuresData = []
    this.seriesNames.forEach((e) => {
      const data = this.chartPivot.map(v => v[e.key]);
      measuresData.push({ name: e.key, data });
      dimensionsData = this.chartPivot.map(v => dayjs(v.x).format('YYYY-MM'))
    });
    // 构建 ve-charts 需要的数据
    const chartData = {
      dimensions: {
        name: 'DateTime',
        data: dimensionsData
      },
      measures: measuresData
    }
    this.chartData = chartData
  }
    ...
}

使用 ve-charts 渲染图表

ve-charts 是基于 Vue2.x 与 ECharts 4.x 构建的图表组件库,用以解决繁杂的 ECharts 配置项以及数据转化带来的烦恼。提供高可配置化、简捷、高效地构建图表组件化方案。

引入 ve-charts

// main.js
import VeCharts from 've-charts'  // 全量引入
import 've-charts/lib/ve-charts.min.css'
    
Vue.use(VeCharts)

在 Vue 工程里可以这样引入组件,比如柱状图:

<ve-bar-chart
  :data="chartData"               // 数据
  :settings="chartSettings"       // 图表配置
  :title="title"                  // 通用配置
/>

数据接口设计

ve-charts 早期在创建时,ECharts 还处于3.x版本,没有 4.x 版本的 dataset API,我们为了统一前后端数据接口,抽离组件数据传参,同时服务于可视化展示需求,于是重新设计了可视化图表的数据传输格式。前文已经提到不再展开。

ve-charts 完整文档点击这里

总结一下

用一张图来说明 Vue Dashboard 是如何渲染可视化图表的

参考

comments powered by Disqus