ECharts接收dataset类型数据封装各类型图形组件

64 篇文章 3 订阅
9 篇文章 0 订阅
该文描述了如何将ECharts图表与matabase接口结合,创建可复用的饼图组件。通过将通用配置和特定选项分离,实现了组件的封装,允许在传入组件名和数据后自动生成图表。示例中展示了如何处理数据格式,配置ECharts的dataset,以及在Vue.js应用中使用这些组件。
摘要由CSDN通过智能技术生成

数据平台整合matabase图表,调用matabase已有接口使用echarts实现图表展示

目标

将各类型图形独立封装为组件
将多个组件整体封装成一个组件
使用时只需传入组件名和对应数据即可

展示

在这里插入图片描述

数据格式

ECharts中dataset配置
在这里插入图片描述

公共组件

在这里插入图片描述

示例饼图 pie-chart

在这里插入图片描述

pie-chart common.js
let commonOption = {
  title: {
    text: '标题',
  },
  legend: {},
  tooltip: {
    trigger: 'item',
  },
  toolbox: {
    show: true,
    feature: {
      saveAsImage: { show: true },
    },
  },
  dataset: {
    dimensions: [],
    source: [],
  },
  // grid: {
  //   top:"0",
  //   bottom: '0',
  //   containLabel: true,
  // },
  series: [
    {
      type: 'pie',
      radius: ['40%', '70%'],
      // center: ['50%', '25%'],
      // label: {
      //   formatter: '{b}: {@2013} ({d}%)',
      // },
      encode: {
        itemName: 'product',
        value: '2013',
        tooltip: [0, 1],
      },
    },
  ],
}
export { commonOption }

pie-chart options.js
import { commonOption } from './common'
import { deepCopy } from '@utils/index'
function getOption(requestData, cardData) {
  console.log('饼图CbnPieChart')
  console.log('requestData', requestData)
  console.log('cardData', cardData)
  let option = deepCopy(commonOption)
  // 数组数据对应字段名
  option.dataset.dimensions = requestData.cols
  // 二维数组数据
  option.dataset.source = requestData.rows
  // 左上角标题
  option.title.text = cardData.name
  // 维度
  let itemName = cardData.visualization_settings['pie.dimension']
  // 衡量标准
  let value = cardData.visualization_settings['pie.metric']
  // 设置series
  option.series = [
    {
      type: 'pie',
      radius: ['40%', '70%'],
      encode: {
        itemName: itemName,
        value: value,
        tooltip: Array.from(Array(requestData.cols.length), (v, k) => k),
      },
    },
  ]
  return option
}
export { getOption }

pie-chart index.vue
<template>
  <div class="chart-box">
    <div class="chart" ref="chart"></div>
  </div>
</template>

<script>
import { getOption } from './option'
import ChartShow from '@mixins/chart-show'
export default {
  name: 'CbnPieChart',
  mixins: [ChartShow(getOption)],
}
</script>
<style lang="scss" scoped>
.chart-box {
  width: 100%;
  height: 100%;

  .chart {
    width: 100%;
    height: 100%;
  }
}
</style>

展示饼图

<div style="width: 100%; height: 800px">
      <cbn-chart :myComponent="myComponent8"></cbn-chart>
</div>
    
import CbnChart from '@components/cbn-chart'
import { data as data8, cardData as cardData8 } from './pieData'
components: {
    CbnChart,
  },
myComponent8: {
        componentName: 'CbnPieChart',
        requestData: data8.data,
        cardData: cardData8,
 },
pieData.js
let data = {
  data: {
    rows: [
      [42, 'Doohickey'],
      [51, 'Gizmo'],
      [53, 'Gadget'],
      [54, 'Widget'],
    ],
    cols: [
      {
        display_name: 'NUM',
        source: 'native',
        field_ref: ['field', 'NUM', { 'base-type': 'type/BigInteger' }],
        name: 'NUM',
        base_type: 'type/BigInteger',
        effective_type: 'type/BigInteger',
      },
      {
        display_name: 'CATEGORY',
        source: 'native',
        field_ref: ['field', 'CATEGORY', { 'base-type': 'type/Text' }],
        name: 'CATEGORY',
        base_type: 'type/Text',
        effective_type: 'type/Text',
      },
    ],
    native_form: {
      query: 'select count(id) num, category from products group by category',
      params: null,
    },
    results_timezone: 'Asia/Shanghai',
    results_metadata: {
      columns: [
        {
          display_name: 'NUM',
          field_ref: ['field', 'NUM', { 'base-type': 'type/BigInteger' }],
          name: 'NUM',
          base_type: 'type/BigInteger',
          effective_type: 'type/BigInteger',
          semantic_type: null,
          fingerprint: {
            global: { 'distinct-count': 4, 'nil%': 0.0 },
            type: {
              'type/Number': {
                min: 42.0,
                q1: 46.5,
                q3: 53.5,
                max: 54.0,
                sd: 5.477225575051661,
                avg: 50.0,
              },
            },
          },
        },
        {
          display_name: 'CATEGORY',
          field_ref: ['field', 'CATEGORY', { 'base-type': 'type/Text' }],
          name: 'CATEGORY',
          base_type: 'type/Text',
          effective_type: 'type/Text',
          semantic_type: null,
          fingerprint: {
            global: { 'distinct-count': 4, 'nil%': 0.0 },
            type: {
              'type/Text': {
                'percent-json': 0.0,
                'percent-url': 0.0,
                'percent-email': 0.0,
                'percent-state': 0.0,
                'average-length': 6.5,
              },
            },
          },
        },
      ],
    },
    insights: null,
  },
  database_id: 1,
  started_at: '2023-01-14T14:53:22.235+08:00',
  json_query: {
    constraints: { 'max-results': 10000, 'max-results-bare-rows': 2000 },
    type: 'native',
    middleware: { 'js-int-to-string?': true, 'ignore-cached-results?': false },
    native: {
      query: 'select count(id) num, category from products group by category',
      'template-tags': {},
    },
    database: 1,
    'async?': true,
    'cache-ttl': null,
  },
  average_execution_time: null,
  status: 'completed',
  context: 'dashboard',
  row_count: 4,
  running_time: 5,
}
let cardData = {
  description: null,
  archived: false,
  collection_position: null,
  table_id: null,
  result_metadata: [
    {
      display_name: 'CATEGORY',
      field_ref: [
        'field',
        'CATEGORY',
        {
          'base-type': 'type/Text',
        },
      ],
      name: 'CATEGORY',
      base_type: 'type/Text',
      effective_type: 'type/Text',
      semantic_type: null,
      fingerprint: {
        global: {
          'distinct-count': 4,
          'nil%': 0.0,
        },
        type: {
          'type/Text': {
            'percent-json': 0.0,
            'percent-url': 0.0,
            'percent-email': 0.0,
            'percent-state': 0.0,
            'average-length': 6.5,
          },
        },
      },
    },
    {
      display_name: 'NUM',
      field_ref: [
        'field',
        'NUM',
        {
          'base-type': 'type/BigInteger',
        },
      ],
      name: 'NUM',
      base_type: 'type/BigInteger',
      effective_type: 'type/BigInteger',
      semantic_type: null,
      fingerprint: {
        global: {
          'distinct-count': 4,
          'nil%': 0.0,
        },
        type: {
          'type/Number': {
            min: 42.0,
            q1: 46.5,
            q3: 53.5,
            max: 54.0,
            sd: 5.477225575051661,
            avg: 50.0,
          },
        },
      },
    },
  ],
  database_id: 1,
  enable_embedding: false,
  collection_id: null,
  query_type: 'native',
  name: 'product-bing',
  query_average_duration: 3,
  creator_id: 5,
  moderation_reviews: [],
  updated_at: '2023-01-14T17:26:07.853',
  made_public_by_id: null,
  embedding_params: null,
  cache_ttl: null,
  dataset_query: {
    type: 'native',
    native: {
      query: 'select category ,count(id) num from products group by category',
      'template-tags': {},
    },
    database: 1,
  },
  id: 37,
  display: 'pie',
  visualization_settings: {
    'pie.show_legend_perecent': true,
    'pie.colors': {
      Doohickey: '#509EE3',
      Gadget: '#F9D45C',
      Gizmo: '#A989C5',
      Widget: '#F2A86F',
    },
    'pie.dimension': 'CATEGORY',
    'pie.metric': 'NUM',
    'table.pivot_column': 'CATEGORY',
    'table.cell_column': 'NUM',
  },
  dataset: false,
  created_at: '2023-01-14T14:11:42.502',
  public_uuid: null,
}
export { data, cardData }

公共index.js

批量获取组件导入整体组件

// 自动加载
const componentsContext = require.context('./', true, /(index\.vue)$/)

let components = {}

componentsContext.keys().forEach((component) => {
  const componentConfig = componentsContext(component)
  components[componentConfig.default.name] = componentConfig.default
})

export const importComponents = components

整体组件index.vue

<template>
  <div class="charts">
    <component v-if="myComponent" :is="myComponent.componentName" v-bind="myComponent" />
  </div>
</template>

<script>
import { importComponents } from './components/index'
export default {
  name: 'Chart',
  components: {
    ...importComponents,
  },
  props: {
    myComponent: {
      type: Object,
      default: function () {
        return null
      },
    },
  },
}
</script>
<style lang="scss" scoped>
.charts {
  width: 100%;
  height: 100%;
}
</style>

mixins写一个混入方法,将公共代码提取出来 chart-show.js

import '@components/cbn-chart/theme-walden.js'
export default function (getOption) {
  return {
    props: {
      requestData: {
        type: Object,
        default: () => {
          return {}
        },
      },
      cardData: {
        type: Object,
        default: () => {
          return {}
        },
      },
    },
    data() {
      return {
        myChart: null,
        option: null,
      }
    },
    mounted() {
      this.reloadChart()
      window.addEventListener('resize', () => {
        this.reloadChart()
      })
    },
    beforeDestroy() {
      this.disposeChart()
    },
    methods: {
      drawChart() {
        this.option = getOption(this.requestData, this.cardData)
        let chartDom = this.$refs.chart
        this.$nextTick(() => {
          this.myChart = this.$echarts.init(chartDom, 'walden')
          this.myChart.setOption(this.option)
          this.myChart.resize()
        })
      },
      // 重新加载图表
      reloadChart() {
        this.disposeChart()
        this.drawChart()
      },
      // 销毁图表以及重置各个数据
      disposeChart() {
        if (this.myChart) {
          this.myChart.dispose()
        }
      },
    },
  }
}

相关代码

链接:https://pan.baidu.com/s/1Ca34Xzp7jtE3nbzpJyNliw
提取码:ozbk

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值