数据平台整合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