echarts天气折线图

效果图:

<template>

  <!-- 天气预报 -->

      <div>

        <el-popover

          placement="bottom"

          popper-class="weather-popver"

          title=""

          trigger="click"

          @hide="handleHideWeather"

        >

        <div class="bigWeather">

          <div class="bigWeather-top">

            <div class="bigWeather-top-txt1">

              <span>当前天气</span>

              <span>&nbsp; | &nbsp;</span>

              <img class="bigWeather-top-icon1" src="@/assets/icon/icon-focus.svg">

              <span>&nbsp; {{ currentWeather.areaName }}</span>

            </div>

            <div class="bigWeather-top-txt2">

              <div class="bigWeather-top-txt2-1">{{ currentWeather.avgTemperature }}°</div>

              <div class="bigWeather-top-txt2-2">{{ currentWeather.dayWeather }}</div>

            </div>

            <div class="bigWeather-top-txt3">

              <div class="bigWeather-top-txt3-1">{{ currentWeather.minTemperature }}~{{ currentWeather.maxTemperature }}°C</div>

              <div class="bigWeather-top-txt3-2">{{ currentWeather.dayWindDirection }}</div>

              <!-- <div class="bigWeather-top-txt3-3">

                <img class="bigWeather-top-txt3-3-1-img" src="@/assets/icon/icon-kq.svg">

                <div class="bigWeather-top-txt3-3-1">空气  &nbsp;优</div>

              </div> -->

            </div>

            <img class="bigWeather-top-txt4" :src="handleWeatherSrc(currentWeather.dayWeather)">

          </div>

          <div class="bigWeather-bottom">

             <div ref="PieChart" class="bigWeather-bottom-echarts"></div>

             <img class="bigWeather-bottom-l" src="@/assets/icon/icon little-unfold-r.svg" @click="scrollToLeft" v-if="!tabScrollShow">

             <img class="bigWeather-bottom-r" v-if="tabScrollShow" src="@/assets/icon/icon little-unfold-l.svg" @click="scrollToRight">

          </div>

        </div>

          <template #reference>

            <div :class="defaultClass=='weather-div'?'weather-div':defaultClass" @click="clickWeather">

              <img class="weather-icon" v-if="handleWeatherSrc(defaultValue.dayWeather)" :src="handleWeatherSrc(defaultValue.dayWeather)">

              <span class="weather-txt1" v-if="defaultValue.avgTemperature">{{defaultValue.avgTemperature}}°</span>

              <span class="weather-txt2">{{defaultValue.dayWeather}}|{{defaultValue.minTemperature}}~{{defaultValue.maxTemperature}}°C</span>

              <img class="weather-icon1" v-if="!weatherVisible" src="@/assets/icon/icon-shouqi222.svg">

              <img class="weather-icon2" v-if="weatherVisible" src="@/assets/icon/icon-shouqi222.svg">

            </div>

          </template>

        </el-popover>

      </div>

</template>

<script>

import * as api from '@apis/common'

import * as echarts from 'echarts'

import clearSkyIcon from '../../../assets/icon/weather/icon-晴天.png'

import blizzardIcon from '../../../assets/icon/weather/icon-暴雪.png'

import heavyRainIcon from '../../../assets/icon/weather/icon-暴雨.png'

import hailIcon from '../../../assets/icon/weather/icon-冰雹.png'

import extremeHeavyRainIcon from '../../../assets/icon/weather/icon-大暴雨.png'

import heavySnowIcon from '../../../assets/icon/weather/icon-大雪.png'

import rainIcon from '../../../assets/icon/weather/icon-大雨.png'

import freezingRainIcon from '../../../assets/icon/weather/icon-冻雨.png'

import cloudyIcon from '../../../assets/icon/weather/icon-多云.png'

import dustIcon from '../../../assets/icon/weather/icon-浮尘.png'

import frostIcon from '../../../assets/icon/weather/icon-降霜.png'

import thunderstormRainIcon from '../../../assets/icon/weather/icon-雷阵雨.png'

import hazeIcon from '../../../assets/icon/weather/icon-霾.png'

import severeDustStormIcon from '../../../assets/icon/weather/icon-强沙尘暴.png'

import dustStormIcon from '../../../assets/icon/weather/icon-沙尘暴.png'

import torrentialRainIcon from '../../../assets/icon/weather/icon-特大暴雨.png'

import darkCloudsIcon from '../../../assets/icon/weather/icon-乌云.png'

import fogIcon from '../../../assets/icon/weather/icon-雾天.png'

import lightSnowIcon from '../../../assets/icon/weather/icon-小雪.png'

import lightRainIcon from '../../../assets/icon/weather/icon-小雨.png'

import sandIcon from '../../../assets/icon/weather/icon-扬沙.png'

import nightIcon from '../../../assets/icon/weather/icon-夜晚.png'

import overcastIcon from '../../../assets/icon/weather/icon-阴天.png'

import drizzleIcon from '../../../assets/icon/weather/icon-阴雨.png'

import raindropIcon from '../../../assets/icon/weather/icon-雨.png'

import sleetIcon from '../../../assets/icon/weather/icon-雨夹雪.png'

import snowShowerIcon from '../../../assets/icon/weather/icon-阵雪.png'

import rainShowerIcon from '../../../assets/icon/weather/icon-阵雨.png'

import moderateSnowIcon from '../../../assets/icon/weather/icon-中雪.png'

import moderateRainIcon from '../../../assets/icon/weather/icon-中雨.png'



export default {

  name: 'Weather',

  components: {

  },

  directives: {},

  props: {

    defaultValue: {

      type: Object,

      default: () => ({})

    },

    defaultClass: {

      type: String,

      default() {

        return 'weather-div'

      }

    }

  },

  filters: {},

  provide: {},

  mixins: [],

  data() {

    return {

      weatherVisible: false,

      currentPointInfo: null,

      tabScrollShow: true,

      currentWeather: {}

    }

  },

  created() {

  },

  methods: {

    handleHideWeather() {

      this.weatherVisible = false

    },

    clickWeather() {

      const t = this

      if (t.weatherVisible) return

      t.weatherVisible = true

      t.tabScrollShow = true

      const req = {

        data: t.defaultValue.datekey,

        shopNo: t.defaultValue.shopNo

      }

      api.weatherInfo(req).then((res) => {

        for (const i in res.data) {

          // eslint-disable-next-line eqeqeq

          if (res.data[i].weekNickName == '今天') {

            t.currentWeather = res.data[i]

          }

        }

        setTimeout(() => {

          const chartDom = t.$refs.PieChart

          t.myChart = echarts.init(chartDom)

          t.myChart.setOption(t.replaceOptionPie(res.data))



          // 监听图表的全局点击事件

          t.myChart.getZr().on('click', (event) => {

            const pointInPixel = [event.offsetX, event.offsetY]

            const pointInGrid = t.myChart.convertFromPixel({ seriesIndex: 0 }, pointInPixel)

            const xIndex = Math.round(pointInGrid[0])



            if (xIndex >= 0 && xIndex < t.myChart.getOption().xAxis[0].data.length) {

              if (t.currentPointInfo) {

                res.data.map((j) => {

                  if (j.weekNickName === t.currentPointInfo[0].name.split(' ')[0]) {

                    t.currentWeather = j

                  }

                })

                // 在这里处理点击事件

              }

            }

          })

          // 监听 dataZoom 事件

          t.myChart.on('dataZoom', (params) => {

            console.log('params', params)

            let startIndex = ''

            let endIndex = ''

            if (params.endValue) { // 直接点击箭头滚动

              startIndex = params.startValue

              endIndex = params.endValue

            } else { // 鼠标滚轮滚动

              const dataLength = res.data.length

              startIndex = Math.round((params.batch[0].start / 100) * dataLength)

              endIndex = Math.round((params.batch[0].end / 100) * dataLength)

            }

            console.log('startIndex', startIndex, endIndex)

            // 更新 rich 属性

            const newRich = t.handleWeatherIcon(res.data.slice(startIndex, endIndex + 1))

            t.myChart.setOption({

              xAxis: [

                {

                  axisLabel: {

                    rich: newRich

                  }

                },

                {

                  axisLabel: {

                    rich: newRich

                  }

                }

              ]

            })

          })



          // 实现窗口变化时,图表的自适应

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

            t.myChart.resize()

          })

        }, 100)

      })

    },

    replaceOptionPie(list) {

      const t = this

      return {

        dataZoom: [

          {

            // 设置滚动条的隐藏与显示

            show: false,

            // 设置滚动条类型

            type: 'slider',

            // 数据窗口范围的起始数值

            startValue: 0,

            // 数据窗口范围的结束数值(一页显示多少条数据)

            endValue: 7,

            // 是否锁定选择区域(或叫做数据窗口)的大小

            zoomLoxk: true,

            // 控制手柄的尺寸

            handleSize: 0,

            // dataZoom-slider组件离容器下侧的距离

            bottom: 3

          },

          {

            // 没有下面这块的话,只能拖动滚动条,

            // 鼠标滚轮在区域内不能控制外部滚动条

            type: 'inside',

            // 滚轮是否触发缩放

            zoomOnMouseWheel: false,

            // 鼠标滚轮触发滚动

            moveOnMouseMove: false,

            moveOnMouseWheel: false

          }

        ],

        grid: {

          left: '5%',

          right: '5%',

          backgroundColor: 'transparent',

          bottom: '3%',

          top: '5px',

          containLabel: true

        },

        tooltip: {

          trigger: 'axis',

          borderWidth: 2,

          backgroundColor: 'rgba(50, 50, 50, 0.7)', // 设置背景颜色

          textStyle: {

            color: '#fff' // 设置文字颜色

          },

          formatter(params) {

            t.currentPointInfo = params // 保存当前点的信息

            return '' // 不显示提示内容

          },

          axisPointer: {

            type: 'shadow', // 使用阴影指示器

            shadowStyle: {

              z: -1,

              color: 'rgba(238, 248, 255, 0.2)' // 设置阴影颜色

            }

          }

        },

        xAxis: [

          {

            type: 'category',

            boundaryGap: false,

            position: 'top',

            offset: 70,

            zlevel: 100,

            axisLine: {

              show: false

            },

            axisTick: {

              show: false

            },

            splitLine: {

              show: false

            },

            axisLabel: {

              fontFamily: 'D-DIN,SAN-SERIF',

              fontSize: '12px',

              fontWeight: 'normal',

              interval: 0,

              color: '#081836',

              formatter(value) {

                // 将 ' ' 替换为 '\n' 进行换行

                return value.replace(' ', '\n')

              }

            },

            // 日期数据

            data: t.handleXaxis(list)

          },

          {

            type: 'category',

            boundaryGap: false,

            position: 'top',

            offset: 20,

            zlevel: 100,

            axisLine: {

              show: false

            },

            axisTick: {

              show: false

            },

            splitLine: {

              show: false

            },

            axisLabel: {

              interval: 0,

              formatter(value, index) {

                // 使用富文本标签来显示图标

                return `{${index}| }\n{icon|}`

              },

              rich: t.handleWeatherIcon(list)

            },

            data: t.handleXaxis(list)

          },

          {

            type: 'category',

            boundaryGap: false,

            position: 'top',

            offset: 0,

            zlevel: 100,

            axisLine: {

              show: false

            },

            axisTick: {

              show: false

            },

            splitLine: {

              show: false

            },

            axisLabel: {

              fontFamily: 'D-DIN,SAN-SERIF',

              fontSize: '12px',

              fontWeight: 'normal',

              interval: 0,

              color: '#081836',

              formatter(value) {

                return `${value}℃`

              }

            },

            // 日期数据

            data: t.handleMaxWeatherList(list)

          },

          {

            type: 'category',

            boundaryGap: false,

            position: 'bottom',

            offset: 0,

            zlevel: 100,

            axisLine: {

              show: false

            },

            axisTick: {

              show: false

            },

            splitLine: {

              show: false

            },

            axisLabel: {

              fontFamily: 'D-DIN,SAN-SERIF',

              fontSize: '12px',

              fontWeight: 'normal',

              interval: 0,

              color: '#081836',

              formatter(value) {

                return `${value}℃`

              }

            },

            // 日期数据

            data: t.handleMaxWeatherList(list)

          }

        ],

        yAxis: [

          {

            type: 'value',

            min: t.handleLineMin(list),

            max: t.handleLineMax(list),

            axisLine: { show: false },

            axisTick: { show: false },

            axisLabel: { show: false },

            splitLine: { show: false }

          }

        ],

        series: [

          {

            name: '温度',

            type: 'line',

            connectNulls: true,

            showSymbol: true, // 去除拐点,未划过时候

            label: {

              show: false,

              color: '#54626F',

              align: 'center',

              formatter: '{c}℃'

            },

            lineStyle: {

              color: '#D1D9E0'

            },

            labelLayout(params) {

              return {

                x: params.rect.x - params.rect.width,

                y: params.rect.y < params.rect.height * 2 ? params.rect.y + params.rect.height * 3 : params.rect.y - params.rect.height,

                verticalAlign: 'middle',

                align: 'left'

              }

            },

            itemStyle: {

              normal: {

                color: '#D1D9E0',

                borderColor: '#D1D9E0',

                borderWidth: 2, // 描边的线宽

                lineStyle: {

                  color: '#D1D9E0', // 折线颜色

                  width: 2 // 折线宽度

                }

              }

            },

            data: t.handleLineData(list)

          }

        ]

      }

    },

    // 处理X轴

    handleXaxis(list) {

      const arr = []

      list.map((i) => {

        arr.push(`${i.weekNickName} ${i.datekey.slice(-4)}`)

      })

      return arr

    },

    // 处理图表折现图的最大值

    handleLineMax(list) {

      const arr = []

      list.map((i) => {

        arr.push(i.avgTemperature)

      })

      return Math.max(...arr) + 2

    },

    // 处理图表折现图的最小值

    handleLineMin(list) {

      const arr = []

      list.map((i) => {

        arr.push(i.avgTemperature)

      })

      return Math.min(...arr) - 2

    },

    // 处理折线图数据

    handleLineData(list) {

      const arr = []

      list.map((i) => {

        arr.push(i.avgTemperature)

      })

      return arr

    },

    // 处理天气折现图标显示

    handleWeatherIcon(list) {

      const t = this

      const rich = {}

      list.forEach((item, index) => {

        rich[index] = {

          backgroundColor: {

            image: t.handleWeatherSrc(item.dayWeather)

          },

          height: 32,

          width: 32

        }

      })

      return rich

    },

    // 获取天气最高温度数组

    handleMaxWeatherList(list) {

      const arr = []

      list.map((i) => {

        arr.push(i.maxTemperature)

      })

      return arr

    },

    // 获取天气最高温度数组

    handleMinWeatherList(list) {

      const arr = []

      list.map((i) => {

        arr.push(i.minTemperature)

      })

      return arr

    },

    handleWeatherSrc(type) {

      const weatherImages = {

        晴: clearSkyIcon,

        霾: hazeIcon,

        暴雪: blizzardIcon,

        小雨: lightRainIcon,

        多云: cloudyIcon,

        大到暴雨: heavyRainIcon,

        雷阵雨: thunderstormRainIcon,

        中雪: moderateSnowIcon,

        冻雨: freezingRainIcon,

        沙尘暴: dustStormIcon,

        扬沙: sandIcon,

        中到大雨: rainIcon,

        小到中雪: moderateSnowIcon,

        强沙尘暴: severeDustStormIcon,

        阴: overcastIcon,

        阵雨: rainShowerIcon,

        雾: fogIcon,

        雷阵雨伴有冰雹: hailIcon,

        大雪: heavySnowIcon,

        暴雨到大暴雨: extremeHeavyRainIcon,

        大雨: rainIcon,

        阵雪: snowShowerIcon,

        小到中雨: moderateRainIcon,

        大暴雨: extremeHeavyRainIcon,

        特大暴雨: torrentialRainIcon,

        中到大雪: heavySnowIcon,

        中雨: moderateRainIcon,

        雨: raindropIcon,

        雨夹雪: sleetIcon,

        浮尘: dustIcon,

        大到暴雪: blizzardIcon,

        小雪: lightSnowIcon,

        暴雨: heavyRainIcon,

        降霜: frostIcon,

        乌云: darkCloudsIcon,

        夜晚: nightIcon,

        阴雨: drizzleIcon

      }



      return weatherImages[type] || ''

    },

    scrollToLeft() {

      if (this.myChart) {

        this.tabScrollShow = !this.tabScrollShow

        this.myChart.dispatchAction({

          type: 'dataZoom',

          startValue: 0,

          endValue: 7

        })

      }

    },

    scrollToRight() {

      if (this.myChart) {

        this.tabScrollShow = !this.tabScrollShow

        const xAxisData = this.myChart.getOption().xAxis[0].data

        const endValue = xAxisData.length - 1

        this.myChart.dispatchAction({

          type: 'dataZoom',

          startValue: endValue - 7,

          endValue

        })

      }

    }



  }

}

</script>



<style lang="scss">

.weather-div {

  display: flex;

  align-items: center;

  height: 2.865vw;

  padding-left: 0.8333vw;

  cursor: pointer;

  position: absolute;

  left: 0;

  top: 0;

  z-index: 20;

  .weather-icon{

    width:46px;

    height:46px;

  }

  .weather-txt2{

    font-family: Roboto-Bold;

    font-size: 14px;

    color: #FFFFFF;

    letter-spacing: 0;

    line-height: 16px;

    font-weight: 700;

    margin-left:4px;

  }

  .weather-txt1 {

    font-family: Roboto-BoldCondensed;

    font-size: 1.66667vw;

    color: #FFFFFF;

    letter-spacing: 0;

    font-weight: 700;

    margin-right: 0.2083vw;

    margin-left:10px;

  }

  .weather-echarts{

      width: 25vw;

      height:5.208vw;

      padding-top:1.8vw;

  }

}

.weather-popver {

  padding: 0 !important;

  width: 552px !important;



  .bigWeather {

    width: 100%;

    height: fit-content;



    .bigWeather-top {

      width: 100%;

      padding-left: 32px;

      padding-top: 32px;

      padding-bottom: 18px;

      background-image: linear-gradient(0deg, #F5FBFF 0%, #EAF7FF 100%);

      border-radius: 4px 4px 0px 0px;

      position: relative;



      .bigWeather-top-txt1 {

        font-family: PingFangSC-Regular;

        font-size: 12px;

        color: #54626F;

        letter-spacing: 0;

        line-height: 14px;

        font-weight: 400;



        .bigWeather-top-icon1 {

          width: 14px;

          height: 14px;

        }

      }



      .bigWeather-top-txt2 {

        margin-top: 16px;

        display: flex;

        align-items: flex-end;



        .bigWeather-top-txt2-1 {

          font-family: Roboto-BoldCondensed;

          font-size: 56px;

          color: #081836;

          letter-spacing: 0;

          line-height: 56px;

          font-weight: 700;

          margin-right: 9px;

        }



        .bigWeather-top-txt2-2 {

          font-family: PingFangSC-Medium;

          font-size: 16px;

          color: #081836;

          letter-spacing: 0;

          line-height: 20px;

          font-weight: 500;

        }

      }



      .bigWeather-top-txt3 {

        margin-top: 18px;

        display: flex;

        align-items: center;



        .bigWeather-top-txt3-1 {

          font-family: Roboto-Regular;

          font-size: 16px;

          color: #081836;

          letter-spacing: 0;

          line-height: 20px;

          font-weight: 400;

          margin-right: 16px;

        }



        .bigWeather-top-txt3-2 {

          font-family: Roboto-Regular;

          font-size: 16px;

          color: #081836;

          letter-spacing: 0;

          line-height: 20px;

          font-weight: 400;

          margin-right: 16px;

        }



        .bigWeather-top-txt3-3 {

          display: flex;

          align-items: center;

          flex-wrap: nowrap;

          background: #DFF0FF;

          border-radius: 4px;

          padding: 2px 6px;



          .bigWeather-top-txt3-3-1-img {

            width: 9px;

            height: 10px;

            margin-right: 3.5px;

          }



          .bigWeather-top-txt3-3-1 {

            font-family: PingFangSC-Regular;

            font-size: 12px;

            color: #0581E3;

            letter-spacing: 0;

            line-height: 16px;

            font-weight: 400;

          }

        }

      }



      .bigWeather-top-txt4 {

        width: 112px;

        height: 112px;

        position: absolute;

        top: 24px;

        right: 46px;

      }

    }



    .bigWeather-bottom {

      width: 100%;

      height: fit-content;

      padding: 24px;

      position: relative;



      .bigWeather-bottom-echarts {

        width: 100%;

        height: 214px;

      }



      .bigWeather-bottom-l {

        background: rgba(255, 255, 255, 0.80);

        box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.16);

        width: 30px;

        height: 30px;

        border-radius: 50%;

        position: absolute;

        left: 9px;

        top: 110px;

        cursor: pointer;

      }



      .bigWeather-bottom-r {

        background: rgba(255, 255, 255, 0.80);

        box-shadow: 0px 2px 6px 0px rgba(0, 0, 0, 0.16);

        width: 30px;

        height: 30px;

        border-radius: 50%;

        position: absolute;

        right: 9px;

        top: 110px;

        cursor: pointer;

      }

    }

  }

}



</style>

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值