Vue3+echarts使用双Y轴折线图

一、父组件代码

<template>

  <div class="stockPrice-trendChart" 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>

    <lineChart

      id="biaxLineChart"

      :chartWidth="chartWidth"

      :chartHeight="chartHeight"

      :options="lineOptions"

      v-show="!showNoData"

    ></lineChart>

  </div>

</template>

<script setup lang="ts">

import { ElMessage } from 'element-plus'

import lineChart from './lineChart.vue'

import type { EChartsOption } from 'echarts'

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

const props = defineProps({

  tagIndex: {

    // tab索引

    type: Number,

    default: null

  },

  securityId: {

    // 证券id

    type: [String, Number],

    required: true

  }

})

const emit = defineEmits(['getChartIndex'])

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

const showNoData = ref(false) // 是否展示无数据图片

const chartWidth = ref('100%')

const chartHeight = ref('300px')

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

// 折线图

const lineOptions: any = ref<EChartsOption>({

  legend: {

    data: [

      { name: '正面' },

      { name: '负面' },

      { name: '股价' },

      {

        name: '股价趋势',

        icon: 'path://M160 544h64v-64h-64v64z m128 0h64v-64h-64v64z m128 0h64v-64h-64v64z m128 0h64v-64h-64v64z m128 0h64v-64h-64v64z m128 0h64v-64h-64v64z' // 自定义图表图例图标

      }

    ]

  },

  xAxis: {

    data: []

  },

  yAxis: [

    {

      type: 'value',

      name: '单位/条',

      position: 'left',

      min: 0,

      max: 0,

      alignTicks: true,

      nameTextStyle: {

        color: '#999999', // 设置字体颜色

        fontSize: 12, // 设置字体大小

        align: 'right' // 设置文本右对齐

      },

      axisLine: {

        lineStyle: {

          color: '#F1F2F5' // 这里设置Y轴刻度线的颜色

        }

      },

      axisLabel: {

        color: '#999999', // 这里设置刻度文字颜色

        align: 'right', // 设置文本右对齐

        // 使用 formatter 函数来格式化刻度标签

        formatter: function (value: any) {

          // 根据实际需求动态控制显示的刻度数字

          if (value % 1 === 0) {

            return value

          } else if (value === 0) {

            return 0

          } else {

            // 如果要隐藏某些刻度,可以返回 ''

            return ''

          }

        }

      }

    },

    {

      type: 'value',

      name: '单位/元',

      position: 'right',

      min: 0,

      max: 0,

      alignTicks: true,

      nameTextStyle: {

        color: '#999999', // 设置字体颜色

        fontSize: 12, // 设置字体大小

        align: 'left' // 设置文本右对齐

      },

      axisLine: {

        lineStyle: {

          color: '#F1F2F5' // 这里设置Y轴刻度线的颜色

        }

      },

      axisLabel: {

        color: '#999999', // 这里设置刻度文字颜色

        // 使用 formatter 函数格式化刻度标签

        formatter: function (value: any) {

          return value.toFixed(4) // 保留四位小数

        }

      }

    }

  ],

  series: [

    {

      name: '正面',

      type: 'line',

      yAxisIndex: 0,

      symbol: 'circle', // 设置标记点形状为圆形

      symbolSize: 4, // 设置标记点大小

      data: [],

      lineStyle: {

        color: '#FFCA52' // 第一条线的颜色

      },

      itemStyle: {

        color: '#FFCA52'

      }

    },

    {

      name: '负面',

      type: 'line',

      yAxisIndex: 0,

      symbol: 'circle', // 设置标记点形状为圆形

      symbolSize: 4, // 设置标记点大小

      data: [],

      lineStyle: {

        color: '#4eebd3' // 第二条线的颜色

      },

      itemStyle: {

        color: '#4eebd3'

      }

    },

    {

      name: '股价',

      type: 'bar',

      yAxisIndex: 1, // 使用第二个坐标轴

      barWidth: 20,

      data: [],

      itemStyle: {

        // 设置圆角大小

        borderRadius: [3, 3, 0, 0],

        color: '#6d9ffe' // 柱状图颜色

      }

    },

    {

      name: '股价趋势',

      type: 'line',

      yAxisIndex: 1,

      symbol: 'circle', // 设置标记点形状为圆形

      symbolSize: 4, // 设置标记点大小

      data: [],

      connectNulls: true, // 设置折线图数据为空时不会断开连接

      lineStyle: {

        type: 'dotted', // 设置为虚线

        color: '#f59999' // 虚线颜色

      },

      itemStyle: {

        color: '#f59999'

      }

    }

  ]

})

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]

    lineOptions.value.xAxis.data = []

    lineOptions.value.legend.data = []

    lineOptions.value.series = [

      {

        name: '正面',

        type: 'line',

        yAxisIndex: 0,

        symbol: 'circle', // 设置标记点形状为圆形

        symbolSize: 4, // 设置标记点大小

        data: [],

        lineStyle: {

          color: '#FFCA52' // 第一条线的颜色

        },

        itemStyle: {

          color: '#FFCA52'

        }

      },

      {

        name: '负面',

        type: 'line',

        yAxisIndex: 0,

        symbol: 'circle', // 设置标记点形状为圆形

        symbolSize: 4, // 设置标记点大小

        data: [],

        lineStyle: {

          color: '#4eebd3' // 第二条线的颜色

        },

        itemStyle: {

          color: '#4eebd3'

        }

      },

      {

        name: '股价',

        type: 'bar',

        yAxisIndex: 1, // 使用第二个坐标轴

        barWidth: 20,

        data: [],

        itemStyle: {

          // 设置圆角大小

          borderRadius: [3, 3, 0, 0],

          color: '#6d9ffe' // 柱状图颜色

        }

      },

      {

        name: '股价趋势',

        type: 'line',

        yAxisIndex: 1,

        symbol: 'circle', // 设置标记点形状为圆形

        symbolSize: 4, // 设置标记点大小

        data: [],

        connectNulls: true, // 设置折线图数据为空时不会断开连接

        lineStyle: {

          type: 'dotted', // 设置为虚线

          color: '#f59999' // 虚线颜色

        },

        itemStyle: {

          color: '#f59999'

        }

      }

    ]

    getStockPrice()

  },

  { deep: true }

)

// 查询舆情与股价变化趋势图

const getStockPrice = () => {

  loading.value = true

  queryStockPrice(currentIndex.value, securityId1.value).then((res: any) => {

    if (res.code === 200) {

      if (res.data) {

        currentIndex.value = res.data.timePeriod

        emit('getChartIndex', currentIndex.value)

        // 判断是否有数据

        if (

          res.data.sentimentTrend.series &&

          res.data.sentimentTrend.series.length > 0

        ) {

          showNoData.value = false

        } else {

          showNoData.value = true

        }

        // 舆情与股价变化趋势图

        lineOptions.value.xAxis.data = res.data.sentimentTrend.xdata

        lineOptions.value.yAxis[0].min = res.data.sentimentTrend.leftMinValue

        lineOptions.value.yAxis[0].max = res.data.sentimentTrend.leftMaxValue

        lineOptions.value.yAxis[1].min = res.data.sentimentTrend.rightMinValue

        lineOptions.value.yAxis[1].max = res.data.sentimentTrend.rightMaxValue

        if (lineOptions.value.yAxis.max === 1) {

          lineOptions.value.yAxis.interval = 1

        }

        res.data.sentimentTrend.series.forEach((i: any) => {

          lineOptions.value.legend.data.push(i.name)

          lineOptions.value.series.forEach((item: any) => {

            if (i.name === item.name) {

              item.data = i.data

            }

          })

        })

      }

    } else {

      ElMessage({

        message: res.message,

        type: 'error'

      })

    }

    loading.value = false

  })

}

onMounted(() => {

  nextTick(() => {

    getStockPrice()

  })

})

</script>

<style lang="less" scoped>

.stockPrice-trendChart {

  margin: 20px 0;

  #biaxLineChart {

    border: 1px solid #ebeef8;

  }

  .no-data {

    width: 100%;

    height: 300px;

    display: flex;

    flex-direction: column;

    justify-content: center;

    border: 1px solid #ebeef8;

    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: 'lineChart'

  },

  chartWidth: {

    type: String,

    default: '600px'

  },

  chartHeight: {

    type: String,

    default: '400px'

  },

  options: {

    type: Object,

    default: () => {}

  }

})

// 定义图表

const lineChart = ref<any>('')

// 图标属性

let chartOptions = {

  tooltip: {

    trigger: 'axis',

    textStyle: {

      fontSize: 12,

      color: '#666666'

    },

    formatter: function (params: any) {

      // params 是一个数组,数组中包含每个系列的数据信息

      let result = `<div style="margin-bottom: 5px;">${params[0].axisValue}<br/></div>`

      params.forEach(function (item: any) {

        // item 是每一个系列的数据

        const seriesName = item.seriesName // 系列名称

        const value = item.value // 数据值

        if (props.id === 'biaxLineChart') {

          // 舆情与股价变化趋势图

          if (seriesName !== '股价趋势') {

            result += `<div style="margin-bottom: 5px; display: flex;align-items: center;"><span style="width: 7px; height: 7px; background-color: ${

              item.color

            }; border-radius: 50%;margin-right: 8px;"></span>${seriesName}:${

              value == null ? '--' : value

            }${

              value == null

                ? ''

                : seriesName === '正面' || seriesName === '负面'

                ? '条'

                : '元'

            }</div>`

          }

        } else if (props.id === 'stockLineChart') {

          // 个股舆情走势图

          result += `<div style="margin-bottom: 5px; display: flex;align-items: center;"><span style="width: 7px; height: 7px; background-color: ${item.color}; border-radius: 50%;margin-right: 8px;"></span>${seriesName}:${value}条</div>`

        } else if (props.id === 'newsLineChart') {

          //新闻指数与评论指数背离趋势图

          result += `<div style="margin-bottom: 5px; display: flex;align-items: center;"><span style="width: 7px; height: 7px; background-color: ${item.color}; border-radius: 50%;margin-right: 8px;"></span>${seriesName}:${value}</div>`

        }

      })

      return result

    }

  },

  legend: {

    top: '5%',

    left: 'center', // 将图例放置在左侧

    icon: 'stack', // 改变或者增加这个为stack,图例会变成矩形。

    itemWidth: 20, // 设置图例标记的宽度

    itemHeight: 3, // 设置图例标记的高度

    itemGap: 40, // 设置图例项之间的距离为40

    itemStyle: {

      borderWidth: 2 // 边框宽度

    },

    data: []

  },

  grid: {

    left: '3%',

    right: '4%',

    bottom: '5%',

    containLabel: true

  },

  toolbox: {

    feature: {

      saveAsImage: false

    }

  },

  xAxis: {

    type: 'category',

    // boundaryGap: false, // 设置数据是否展示在刻度上

    axisLine: {

      lineStyle: {

        color: '#D7D9DF' // 这里设置X轴刻度线的颜色

      }

    },

    axisLabel: {

      color: '#999999' // 这里设置刻度文字颜色

    },

    data: []

  },

  series: []

}

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

watch(props.options, (newVal) => {

  if (lineChart.value) {

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

    lineChart.value.clear()

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

    chartOptions.xAxis.data = []

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

      item.data = []

    })

    //执行merge合并时,后面的props.options会覆盖chartOptions内相同字段内容,并返回chartOptions

    _.merge(chartOptions, newVal)

    lineChart.value.setOption(chartOptions)

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

    setTimeout(() => {

      lineChart.value.resize()

    })

  }

})

onMounted(() => {

  lineChart.value = markRaw(

    echarts.init(document.getElementById(props.id) as HTMLDivElement)

  )

  // 大小自适应

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

    lineChart.value.resize()

  })

})

onActivated(() => {

  if (lineChart.value) {

    lineChart.value.resize()

  }

})

</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值