-
Notifications
You must be signed in to change notification settings - Fork 6
Open
Description
2B的报表组件
主要使用 frappe-chart 组件,对其做了一个简单封装。主要提供以下几个功能。
- 图形的放大
- 图片的导出,可导出svg格式和导出excel表格(自己封装的一个组件)
- 插槽添加扩展按钮
- 显示最大值 最小值 平均值
- 对单点数据错误做了处理
- byte上的包解决import 错误和 stacked bar 在0值的ui问题
主要属性
chartData: {}
chartConfig:{}chartData与chartConfig设置和官网一样 主要增加如下配置
chartConfig: {
btnOptions: {
sizeBtn: false,//{ show: true,}
exportBtn: { show: true, type: 'data', xlabel: '时间' }
},
showMax_Min_Mean: {
max: false,
min: false,
mean: false
}}组件比较简短粗燥 ,所以直接端上来了。
<template>
<div :class="{component_chart:true,chartLarge:hasLarged}"
v-if="chartShow">
<div class="chartWrap"
ref="chartWrap">
<div class="chart"
ref="chart">
</div>
<!-- 扩展的按钮 -->
<div class="anatherBtn">
<slot>
</slot>
</div>
<div :class="{largeBtn:(chartConfig.btnOptions||{}).sizeBtn, chartBtn:true}"
@click="changeSize"
v-if="(chartConfig.btnOptions||{}).sizeBtn">
<i class="el-icon-rank"></i>
</div>
<div :class="{downloadBtn:(chartConfig.btnOptions||{}).exportBtn, chartBtn:true}"
@click="exportChart"
v-if="((chartConfig.btnOptions||{}).exportBtn||{}).show&&chartConfig.btnOptions.exportBtn.type=='pic'">
<i class="el-icon-download"></i>
</div>
<out-put :class="{downloadBtn:(chartConfig.btnOptions||{}).exportBtn, chartBtn:true}"
:params="outputParams"
v-if="((chartConfig.btnOptions||{}).exportBtn||{}).show&&chartConfig.btnOptions.exportBtn.type=='data'">
<i class="el-icon-download"></i>
</out-put>
</div>
</div>
</template>
<script>
import _ from 'lodash'
import OutPut from '~/components/common/outputXLSX'
import { Chart } from 'frappe-charts'
export default {
data() {
return {
chartShow: true,
chartDom: {},
hasLarged: false,
chart: {},
config: {}
}
},
props: {
chartData: { type: Object, default: () => ({}) },
chartConfig: { type: Object, default: () => ({}) }
},
computed: {
outputParams() {
let jsonData = []
let keyMap = {
xlabel: ((this.chartConfig.btnOptions || {}).exportBtn || {}).xlabel
}
//验证数据格式
if (
!(
Array.isArray(this.chartData.datasets) &&
this.chartData.datasets.length &&
Array.isArray(this.chartData.labels) &&
this.chartData.labels.length
)
) {
return { jsonData, keyMap }
}
this.chartData.datasets.forEach((line, index) => {
keyMap['key' + index] = line.name
})
this.chartData.labels.forEach((x, i) => {
let oneRow = {}
oneRow.xlabel = x
this.chartData.datasets.forEach((line, index) => {
oneRow['key' + index] = line.values[i]
})
jsonData.push(oneRow)
})
return { jsonData, keyMap, fileName: this.chartConfig.title }
}
},
watch: {
chartData(newValue, oldValue) {
let chartDom = this.$refs.chart
if (
Array.isArray(newValue.labels) &&
Array.isArray(oldValue.labels) &&
newValue.labels.length == oldValue.labels.length &&
newValue.datasets.length == oldValue.datasets.length
) {
this.chart.update(newValue)
} else {
this.initChart()
}
}
},
components: { OutPut },
methods: {
changeSize() {
this.hasLarged = !this.hasLarged
if (this.hasLarged) {
this.$set(this.config, 'height', this.config.height * 2)
} else {
this.$set(this.config, 'height', this.chartConfig.height)
}
this.initChart(true)
},
exportChart() {
this.chart.export()
},
initChart(isSize) {
if (!isSize) {
this.config = _.cloneDeep(this.chartConfig)
}
//验证数据格式
if (
!(
Array.isArray(this.chartData.datasets) &&
this.chartData.datasets.length &&
Array.isArray(this.chartData.labels) &&
this.chartData.labels.length
)
) {
return
}
//单点情况
if (this.chartData.labels.length == 1) {
this.chartData.labels.push('')
if (this.config.type == 'line') {
this.config.lineOptions = {
dotSize: 4,
hideDots: 0
}
} else if (this.config.type == 'bar') {
this.config.barOptions = {}
}
} else {
if (!isSize) {
this.config = _.cloneDeep(this.chartConfig)
}
}
let allData = []
this.chartData.datasets.forEach(element => {
allData.push(...element.values)
})
//确保坐标最大值和最小值能显示
if (this.chartConfig.showMax_Min_Mean) {
if (
!(this.chartData.yMarkers && Array.isArray(this.chartData.yMarkers))
) {
this.chartData.yMarkers = []
}
if (this.chartConfig.showMax_Min_Mean.max) {
this.chartData.yMarkers.push({
label: 'max',
value: Math.max(...allData),
options: { labelPos: 'left' }
})
}
if (this.chartConfig.showMax_Min_Mean.min) {
this.chartData.yMarkers.push({
label: 'min',
value: Math.min(...allData),
options: { labelPos: 'left' }
})
}
if (this.chartConfig.showMax_Min_Mean.mean) {
let sum = 0
allData.forEach(item => {
sum += item
})
this.chartData.yMarkers.push({
label: 'mean',
value: sum / allData.length,
options: { labelPos: 'left' }
})
}
}
if (
this.chartData.labels.length < 15 &&
this.config.lineOptions &&
!this.config.lineOptions.hideDots
) {
this.chartConfig.lineOptions.dotSize = 4
}
setTimeout(() => {
this.chart = new Chart(this.chartDom, {
data: this.chartData,
...this.config
})
}, 50)
}
},
mounted() {
let chartDom = this.$refs.chart
this.chartDom = chartDom
this.initChart()
},
beforeDestroy() {
//离开时候 注销chart
if (
this.chart.unbindWindowEvents &&
typeof this.chart.unbindWindowEvents == 'function'
) {
this.chart.unbindWindowEvents()
}
}
}
</script>
<style lang="stylus">
.chart
.frappe-chart.chart
text.title
font-size 14px
fill rgb(34 34 34)
</style>
<style scoped lang="stylus">
.component_chart
font-family 'PingFangSC-Regular'
display flex
flex-direction column
justify-content center
width 100%
overflow hidden
.chartWrap
position relative
text-align center
overflow hidden
.chart
width 100%
.chartBtn
font-size 18px
padding 2px 5px
position absolute
color rgb(182 192 226)
&:hover
cursor pointer
.largeBtn
top 10px
right 1px
.downloadBtn
bottom 0px
right 1px
.anatherBtn
position absolute
top 4px
left 115px
// top 10px
// right 60px
.chartLarge
width 970px
height 500px
.largeBtn
top 10px
right 20px!important
.downloadBtn
bottom 0px
right 20px!important
</style>
Metadata
Metadata
Assignees
Labels
No labels