气象相关图表制作-字体图标、图片、折线的堆叠

开发工作中有个需要展示气温(折线)、天气(图片)、风羽(字体图标)的图表展示需求,之前用过highcharts的关于类似的chart,里面的风雨用的是自带的图片,但是现在要求风羽需要用字体图标渲染,于是我选择了比较熟悉的Echarts制作这个图表。

难点

  1. 风羽(字体图标)不仅需要显示,还需要旋转,但是旋转的时,风羽会偏移
  2. 各类元素之间需要分层显示

代码

/**
* SouthAsiaViewHighImpactWeatherSingleAirportChart.vue 逐3小时天气预报图
* @Author ZhangJun
* @Date  2024/6/19 10:18
**/
<template>
  <div class="w-full h-full"></div>
</template>
<script>
import * as echarts from 'echarts';
import CanvasGridUtils from "@/utils/leaflet/CanvasGridUtils";
import moment from "moment/moment";

export default {
  name: 'SouthAsiaViewHighImpactWeatherSingleAirportChart',
  data() {
    return {
      chartOption: {
        grid: {
          left: '5%',
          right: '5%',
          bottom: '3%',
          top: '5px',
          containLabel: true
        },
        tooltip: {
          trigger: 'axis',
          backgroundColor: 'rgba(0, 38, 72, 0.9)',
          borderColor: 'rgba(141, 180, 255, 0.31)',
          borderWidth: 2,
          formatter: (params) => {
            let [temperatureParams, weatherParams, windParams, levelParams] = params;
            let date = moment(temperatureParams?.name, 'YYYYMMDDHHmm').format('YYYY-MM-DD HH:mm');

            //温度值
            let temperatureValue = `${temperatureParams?.value}`;
            let temperatureMarker = temperatureParams?.marker;

            //天气
            let weatherValue = weatherParams?.value?.[2];
            let weatherMarker = weatherParams?.data.symbol;

            //风向/风力
            let windMarker = CanvasGridUtils.GetWindChar(windParams?.value?.[1]);
            let rotate = -windParams?.data.label.rotate;
            let levelValue = `${levelParams?.value?.[1]}`;
            return [
              `<div style="font-size: 14px; color: #FFFFFF;font-weight: bold;">
                 ${date}
                </div>`,
              `<div style="display: flex; justify-content: space-between; align-items: center;">
                 <div style="padding: 0 10px;">${temperatureMarker}</div><div style="font-size: 12px; color: #FFFFFF;">${temperatureValue}</div>
                </div>`,
              `<div style="display: flex; justify-content: space-between; align-items: center;">
                  <img src="${weatherMarker.replace('image://', '')}" alt="${weatherValue}" style="width: 30px; height: 30px;"><div  style="font-size: 12px; color: #FFFFFF;">${weatherValue}</div>
                </div>`,
              `<div style="display: flex; justify-content: space-between; align-items: center;">
                  <div style="transform: rotate(${rotate}deg);font-size: 30px;font-weight: bold;color: #FFFFFF;">${windMarker}</div><div style="font-size: 12px; color: #FFFFFF;">${levelValue}</div>
                </div>`
            ].join('');
          }
        },
        xAxis: {
          type: 'category',
          boundaryGap: false,
          axisLine: {
            show: false
          },
          axisTick: {
            show: false
          },
          splitLine: {
            show: false
          },
          axisLabel: {
            fontFamily: 'D-DIN,SAN-SERIF',
            fontSize: '12px',
            fontWeight: 'normal',
            color: '#FFFFFF',
            formatter: (value) => {
              return value ? moment(value, 'YYYYMMDDHHmm').format('HH:mm') : '';
            },
          },
          //日期数据
          data: ['202406280000', '202406280300', '202406280600', '202406280900', '202406281200', '202406281500', '202406281800', '202406282100']
        },
        yAxis: [
          {
            type: 'value',
            axisLine: {show: false},
            axisTick: {show: false},
            axisLabel: {show: false},
            splitLine: {show: false},
            min: -120,
            max: 60,
          },
          {
            type: 'value',
            axisLine: {show: false},
            axisTick: {show: false},
            axisLabel: {show: false},
            splitLine: {show: false},
            min: 0,
            max: 100,
          }
        ],
        series: [
          {
            name: '温度',
            type: 'line',
            yAxisIndex: 0,
            label: {
              show: true,
              color: '#fff',
              align: 'center',
              formatter: '{c}℃'
            },
            lineStyle: {
              color: '#FFBC1E'
            },
            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'
              }
            },
            data: [-10, -12, 11, 13, 60, 23, 21, 11]
          },
          //天气
          {
            name: 'weather',
            type: 'pictorialBar',
            yAxisIndex: 1,
            symbolSize: 30,
            symbolOffset: [0, -65],
            label: {
              show: true,
              fontSize: 12,
              color: '#fff',
              offset: [0, -10],
              formatter: ({value}) => {
                return value?.[2];
              },
            },
            data: [
              {
                value: ['202406280000', 0, '晴'],
                symbol: `image://${require('@/assets/images/weather/晴.png')}`,
              },
              {
                value: ['202406280300', 0, '晴'],
                symbol: `image://${require('@/assets/images/weather/晴.png')}`,
              },
              {
                value: ['202406280600', 0, '多云'],
                symbol: `image://${require('@/assets/images/weather/多云.png')}`,
              },
              {
                value: ['202406280900', 0, '晴'],
                symbol: `image://${require('@/assets/images/weather/晴.png')}`,
              },
              {
                value: ['202406281200', 0, '晴'],
                symbol: `image://${require('@/assets/images/weather/晴.png')}`,
              },
              {
                value: ['202406281500', 0, '阵雨'],
                symbol: `image://${require('@/assets/images/weather/阵雨.png')}`,
              },
              {
                value: ['202406281800', 0, '阴'],
                symbol: `image://${require('@/assets/images/weather/阴.png')}`,
              },
              {
                value: ['202406282100', 0, '晴'],
                symbol: `image://${require('@/assets/images/weather/晴.png')}`,
              },
            ]
          },
          //绘制风羽
          {
            name: 'winBarb',
            type: 'pictorialBar',
            yAxisIndex: 1,
            symbolSize: [0, 65],
            label: {
              show: true,
              fontFamily: 'iconfont',
              fontSize: 30,
              fontWeight: 'bold',
              color: '#fff',
              formatter: ({value}) => {
                return CanvasGridUtils.GetWindChar(value?.[1]);
              },
            },
            data: [{
              value: ['202406280000', 10],
              label: {
                rotate: -180,
              },
            }, {
              value: ['202406280300', 10],
              label: {
                rotate: 0,
              },
            }, {
              value: ['202406280600', 10],
              label: {
                rotate: -90,
              },
            }, {
              value: ['202406280900', 10],
              label: {
                rotate: -200,
              },
            }, {
              value: ['202406281200', 10],
              label: {
                rotate: -180,
              },
            }, {
              value: ['202406281500', 10],
              label: {
                rotate: -180,
              },
            }, {
              value: ['202406281800', 10],
              label: {
                rotate: -180,
              },
            }, {
              value: ['202406282100', 10],
              label: {
                rotate: -180,
              },
            }]
          },
          // 绘制风力等级图标
          {
            name: 'winLevel',
            type: 'pictorialBar',
            yAxisIndex: 1,
            symbolSize: [0, 20],
            label: {
              show: true,
              fontSize: 12,
              fontFamily: 'MiSans, sans-serif',
              color: '#fff',
              align: 'center',
              formatter: ({value}) => {
                let level = value?.[1];
                return `${level}`;
              },
            },
            data: [
              ['202406280000', 3],
              ['202406280300', 3],
              ['202406280600', 4],
              ['202406280900', 5],
              ['202406281200', 4],
              ['202406281500', 3],
              ['202406281800', 4],
              ['202406282100', 3],
            ]
          }
        ]
      }
    }
  },
  methods: {
    /**
     * 初始化图表
     */
    initChart() {
      echarts.init(this.$el).setOption(this.chartOption);
    },
  },
  mounted() {
    this.$nextTick(() => {
      this.initChart();
    });
  }
}
</script>

效果

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端程序员_花姐夫Jun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值