开发工作中有个需要展示气温(折线)、天气(图片)、风羽(字体图标)的图表展示需求,之前用过highcharts的关于类似的chart,里面的风雨用的是自带的图片,但是现在要求风羽需要用字体图标渲染,于是我选择了比较熟悉的Echarts制作这个图表。
难点
- 风羽(字体图标)不仅需要显示,还需要旋转,但是旋转的时,风羽会偏移
- 各类元素之间需要分层显示
代码
/**
* 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>