Vue3+echarts使用词云图与仪表盘

一、父组件代码

<template>

  <div class="commentDynamicMonitoring" v-loading="loading">

    <div class="no-data" v-show="showNoData">

      <img src="@/assets/img/no_data.png" alt="" class="img" />

      <div class="noData-text">暂无数据</div>

    </div>

    <wordCloud

      id="wordCloudChart"

      :chartWidth="chartWidth"

      :chartHeight="chartHeight"

      :colorList="colorList"

      :options="wordCloudOptions"

      v-show="!showNoData"

    ></wordCloud>

    <div class="right-box">

      <infoTitle infoTitle="情绪指数" class="info-chart"></infoTitle>

      <instrumentChart

        id="instrumentChart"

        chartWidth="100%"

        chartHeight="255px"

        :colorList="colorList1"

        :options="instrumentChartOptions"

      ></instrumentChart>

      <infoTitle infoTitle="评论信息" class="info-chart"></infoTitle>

      <div class="detail-info">

        <div class="title">{{ detailTitle }}</div>

        <el-popover

          placement="top-start"

          :width="500"

          trigger="hover"

          :content="detailInfo"

          popper-class="switch-popper"

          v-if="showTooltip"

        >

          <template #reference>

            <span class="detail" @mouseenter="isShowTooltip($event)">{{

              detailInfo

            }}</span>

          </template>

        </el-popover>

        <span class="detail" @mouseenter="isShowTooltip($event)" v-else>{{

          detailInfo

        }}</span>

      </div>

    </div>

  </div>

</template>

<script setup lang="ts">

import { ElMessage } from 'element-plus'

import wordCloud from './wordCloud.vue'

import infoTitle from './infoTitle.vue'

import instrumentChart from './instrumentChart.vue'

import 'echarts-wordcloud'

import type { EChartsOption } from 'echarts'

import { queryCommentDynamicMonitoring } from '@/service/stockIndex/index'

const props = defineProps({

  tagIndex: {

    // tab索引

    type: Number,

    default: 0

  },

  securityId: {

    // 证券id

    type: [String, Number],

    required: true

  }

})

const loading = ref(false) // 加载状态

const showNoData = ref(false)

const chartWidth = ref('900px')

const chartHeight = ref('500px')

const showTooltip = ref(false) // 是否展示浮框

const currentIndex = ref(props.tagIndex) // 定义新tab索引值接收

const detailTitle = ref('')

const detailInfo = ref('')

// 词语图颜色定义

const colorList = ref<any>([

  '#27D38A',

  '#FFCA1C',

  '#5DD1FA',

  '#F88E25',

  '#47A0FF',

  '#FD6565'

])

// 仪表盘颜色定义

const colorList1 = ref<any>([

  [0.1, '#1ec569'],

  [0.2, '#72cd65'],

  [0.3, '#9fcc58'],

  [0.4, '#a5c852'],

  [0.5, '#d6c949'],

  [0.6, '#fcb743'],

  [0.7, '#fe984a'],

  [0.8, '#fe7c4f'],

  [0.9, '#fe6b55'],

  [1, '#fe4a41']

])

// 词语图属性定义

const wordCloudOptions: any = ref<EChartsOption>({

  series: [

    {

      data: []

    }

  ]

})

// 仪表盘图表属性定义

const instrumentChartOptions: any = ref<EChartsOption>({

  series: [

    {

      data: []

    }

  ]

})

const securityId1 = ref(props.securityId) // 页面新的证券id

// 监听参数重新赋值

watch(

  () => [props.securityId, props.tagIndex],

  (newValue: any, oldValue: any) => {

    if (newValue[0] != oldValue[0]) {

      securityId1.value = newValue[0]

    }

    currentIndex.value = newValue[1]

    wordCloudOptions.value.series[0].data = []

    instrumentChartOptions.value.series[0].data = []

    detailTitle.value = ''

    detailInfo.value = ''

    getCommentDynamicMonitoring()

  },

  { deep: true }

)

// 判断是否展示文本浮框

const isShowTooltip = (event: any) => {

  const ev = event.target

  const evHeight = ev.scrollHeight

  const contentHeight = ev.clientHeight

  if (evHeight > contentHeight) {

    // 实际宽度 > 可视宽度  文字溢出

    showTooltip.value = true

  } else {

    // 否则为不溢出

    showTooltip.value = false

  }

}

// 查询词云图数据、情绪指数、评论信息

const getCommentDynamicMonitoring = () => {

  loading.value = true

  queryCommentDynamicMonitoring(currentIndex.value, securityId1.value).then(

    (res: any) => {

      if (res.code === 200) {

        if (res.data) {

          // 判断是否有数据

          if (res.data.wordClouds && res.data.wordClouds.length > 0) {

            showNoData.value = false

          } else {

            showNoData.value = true

          }

          // 词云图数据

          wordCloudOptions.value.series[0].data = res.data.wordClouds

          // 看涨看跌指数

          instrumentChartOptions.value.series[0].data = [

            {

              name: '',

              value: res.data.sentimentIndex,

              emphasis: {

                // 设置 normal 和 emphasis 状态下的颜色保持一致

                itemStyle: {

                  color: 'inherit'

                }

              }

            }

          ]

          // 评论数据

          detailTitle.value = res.data.shortName

          detailInfo.value = res.data.overview

        }

      } else {

        ElMessage({

          message: res.message,

          type: 'error'

        })

      }

      loading.value = false

    }

  )

}

onMounted(() => {

  nextTick(() => {

    getCommentDynamicMonitoring()

  })

})

</script>

<style lang="less" scoped>

.commentDynamicMonitoring {

  display: flex;

  margin: 24px 0 20px;

  #wordCloudChart {

    border: 1px solid #ebeef8;

  }

  .right-box {

    width: 511px;

    background: #ffffff;

    border-right: 1px solid #ebeef8;

    border-bottom: 1px solid #ebeef8;

    #instrumentChart {

      border-bottom: 1px solid #ebeef8;

    }

    .detail-info {

      margin: 0 22px;

      .title {

        margin: 12px 0 5px 0;

        font-size: 16px;

        color: #333333;

        font-weight: 600;

      }

      .detail {

        font-weight: 500;

        font-size: 14px;

        color: #666666;

        line-height: 22px;

        overflow: hidden;

        text-overflow: ellipsis;

        display: -webkit-box;

        -webkit-line-clamp: 5;

        line-clamp: 5;

        -webkit-box-orient: vertical;

      }

    }

  }

  .no-data {

    width: 100%;

    height: 500px;

    border: 1px solid #ebeef8;

    display: flex;

    flex-direction: column;

    justify-content: center;

    align-items: center;

    .img {

      width: 300px;

      height: 163px;

      margin-bottom: 10px;

    }

    .noData-text {

      font-size: 12px;

      color: #cacfd7;

    }

  }

}

</style>

二、词云图组件代码

<template>

  <div :id="id" :style="{ width: chartWidth, height: chartHeight }"></div>

</template>

<script setup lang="ts">

import * as echarts from 'echarts'

import _ from 'lodash'

const props = defineProps({

  id: {

    type: String,

    default: 'wordCloudChart'

  },

  chartWidth: {

    type: String,

    default: '353px'

  },

  chartHeight: {

    type: String,

    default: '300px'

  },

  colorList: {

    // 词云图颜色

    type: Array,

    default: () => []

  },

  options: {

    type: Object,

    default: () => {}

  }

})

// 定义图表

const wordCloudChart = ref<any>('')

// 图表渲染参数开始

let chartOptions = {

  tooltip: {

    show: false

  },

  grid: {

    left: '0%',

    right: '0%',

    top: '0%',

    bottom: '0%',

    containLabel: true

  },

  series: [

    {

      type: 'wordCloud',

      gridSize: 1,

      sizeRange: [12, 100],

      rotationRange: [0, 0],

      textStyle: {

        color: function () {

          let num = Math.floor(Math.random() * (5 + 1))

          return props.colorList[num]

        }

      },

      left: 'center',

      top: 'center',

      width: '96%',

      height: '50%',

      data: []

    }

  ]

}

//监听options变化,给图表赋值

watch(

  props.options,

  (newValue) => {

    if (wordCloudChart.value) {

      //当数据有更新时候,可使用lineChart.value.clear()清除现有的图表状态,然后再应用新的配置。

      wordCloudChart.value.clear()

      //数据清空,因为使用_.merge合并时,会残留历史数据

      chartOptions.series.forEach((item: any) => {

        item.data = []

      })

      _.merge(chartOptions, newValue)

      wordCloudChart.value.setOption(chartOptions)

        // 监听窗口大小变化,自动调整图表大小

      setTimeout(() => {

        wordCloudChart.value.resize()

      })

    }

  },

  { deep: true }

)

onMounted(() => {

  // 初始化 ECharts 实例

  wordCloudChart.value = echarts.init(

    document.getElementById(props.id) as HTMLDivElement

  )

  // 设置 ECharts 配置项

  wordCloudChart.value.setOption(chartOptions)

  // 监听窗口大小变化,自动调整图表大小

  window.addEventListener('resize', () => {

    wordCloudChart.value.resize()

  })

})

onUnmounted(() => {

  // 销毁 ECharts 实例

  wordCloudChart.value.dispose()

  // 移除窗口大小变化监听器

  window.removeEventListener('resize', () => wordCloudChart.value.resize())

})

</script>

三、仪表盘组件代码

<template>

  <div :id="id" :style="{ width: chartWidth, height: chartHeight }"></div>

</template>

<script setup lang="ts">

import * as echarts from 'echarts'

import _ from 'lodash'

const props = defineProps({

  id: {

    type: String,

    default: 'instrumentChart'

  },

  chartWidth: {

    type: String,

    default: '511px'

  },

  chartHeight: {

    type: String,

    default: '300px'

  },

  options: {

    type: Object,

    default: () => {}

  },

  colorList: {

    type: Array,

    default: () => []

  }

})

// 定义图表

const instrumentChart = ref<any>('')

// 图表渲染参数开始

let chartOptions = {

  tooltip: {

    show: false

  },

  series: [

    {

      name: '情绪指数',

      type: 'gauge',

      center: ['50%', '75%'],

      startAngle: 180, // 开始角度,水平方向从正上方开始

      endAngle: 0, // 结束角度,水平方向从正下方结束

      radius: '100%',

      min: 0,

      max: 100,

      axisLine: {

        lineStyle: {

          width: 18, // 设置宽度以适应半径

          height: 30, // 设置高度以适应半径

          color: props.colorList

        }

      },

      axisTick: {

        distance: -18,

        length: 20,

        splitNumber: 1,

        lineStyle: {

          color: '#fff',

          width: 1

        }

      },

      splitLine: {

        show: true,

        length: 18, // 设置仪表盘分割线线长

        lineStyle: {

          color: 'white' // 设置仪表盘分割线颜色

        }

      },

      axisLabel: {

        distance: -5,

        color: 'inherit',

        fontSize: 12,

        // 设置仪表盘刻度

        formatter: function (e: any) {

          switch (e + '') {

            case '10':

              return '10'

            case '20':

              return '20'

            case '30':

              return '30'

            case '40':

              return '40'

            case '50':

              return '50'

            case '60':

              return '60'

            case '70':

              return '70'

            case '80':

              return '80'

            case '90':

              return '90'

            case '100':

              return '100'

            default:

              return e

          }

        }

      },

      pointer: {

        // show: true,

        // showAbove: true, // 指针是否显示在标题和仪表盘详情上方。

        // offsetCenter: [-10, 0], // 相对于仪表盘中心的偏移位置,数组第一项是水平方向的偏移,第二项是垂直方向的偏移。可以是绝对的数值,也可以是相对于仪表盘半径的百分比。

        // length: '40%', // 指针长度,可以是绝对数值,也可以是相对于半径的半分比。

        // width: 8, // 指针宽度。

        itemStyle: {

          // 指针样式

          color: 'inherit'

        }

      },

      detail: {

        offsetCenter: [0, 25], // 设置仪表盘中心文本位置

        fontSize: 18, // 设置仪表盘中心文本字体大小

        color: 'inherit' // 设置仪表盘中心文本颜色跟随刻度文本颜色

      },

      data: []

    }

  ]

}

//监听options变化,给图表赋值

watch(

  props.options,

  (newValue) => {

    if (instrumentChart.value) {

      //当数据有更新时候,可使用lineChart.value.clear()清除现有的图表状态,然后再应用新的配置。

      instrumentChart.value.clear()

      //数据清空,因为使用_.merge合并时,会残留历史数据

      chartOptions.series.forEach((item: any) => {

        item.data = []

      })

      _.merge(chartOptions, newValue)

      instrumentChart.value.setOption(chartOptions)

        // 监听窗口大小变化,自动调整图表大小

      setTimeout(() => {

        instrumentChart.value.resize()

      })

    }

  },

  { deep: true }

)

onMounted(() => {

  // 初始化 ECharts 实例

  instrumentChart.value = echarts.init(

    document.getElementById(props.id) as HTMLDivElement

  )

  // 设置 ECharts 配置项

  instrumentChart.value.setOption(chartOptions)

  // 监听窗口大小变化,自动调整图表大小

  window.addEventListener('resize', () => {

    instrumentChart.value.resize()

  })

  // 监听轴标签颜色变化

  instrumentChart.value.on('updateAxisPointer', function (event: any) {

    if (event.axisType === 'category') {

      let axisPointer = event.axisPointer

      let tickColor = axisPointer.axis.axisTick.lineStyle.color

      // 更新 detail 标签的颜色

      instrumentChart.value.setOption({

        series: [

          {

            formatter: 'text',

            textStyle: {

              color: tickColor

            }

          }

        ]

      })

    }

  })

})

onUnmounted(() => {

  // 销毁 ECharts 实例

  instrumentChart.value.dispose()

  // 移除窗口大小变化监听器

  window.removeEventListener('resize', () => instrumentChart.value.resize())

})

</script>

infoTitle组件代码参考上篇博文
上一篇:ssh远程连接服务器


下一篇:Redis的持久化机制