Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chart in 2b project #24

Open
deligent-ant opened this issue Oct 25, 2018 · 0 comments
Open

chart in 2b project #24

deligent-ant opened this issue Oct 25, 2018 · 0 comments

Comments

@deligent-ant
Copy link
Contributor

2B的报表组件

主要使用 frappe-chart 组件,对其做了一个简单封装。主要提供以下几个功能。

  1. 图形的放大
  2. 图片的导出,可导出svg格式和导出excel表格(自己封装的一个组件)
  3. 插槽添加扩展按钮
  4. 显示最大值 最小值 平均值
  5. 对单点数据错误做了处理
  6. 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant