效果如下:
代码如下:
import option from './option.js';
import * as echarts from "echarts";
import { useEffect,useRef } from "react";
const App = () => {
const chartRef = useRef(null);
useEffect(() => {
init()
}, [])
// 数据来自和风API
let data = [
{
"fxDate": "2024-12-29",
"sunrise": "07:36",
"sunset": "16:58",
"moonrise": "06:07",
"moonset": "15:03",
"moonPhase": "残月",
"moonPhaseIcon": "807",
"tempMax": "5",
"tempMin": "-5",
"iconDay": "101",
"textDay": "多云",
"iconNight": "150",
"textNight": "晴",
"wind360Day": "270",
"windDirDay": "西风",
"windScaleDay": "1-3",
"windSpeedDay": "3",
"wind360Night": "315",
"windDirNight": "西北风",
"windScaleNight": "1-3",
"windSpeedNight": "3",
"humidity": "26",
"precip": "0.0",
"pressure": "1014",
"vis": "25",
"cloud": "0",
"uvIndex": "2"
},
{
"fxDate": "2024-12-30",
"sunrise": "07:36",
"sunset": "16:59",
"moonrise": "07:07",
"moonset": "15:55",
"moonPhase": "残月",
"moonPhaseIcon": "807",
"tempMax": "7",
"tempMin": "-5",
"iconDay": "100",
"textDay": "晴",
"iconNight": "150",
"textNight": "晴",
"wind360Day": "315",
"windDirDay": "西北风",
"windScaleDay": "1-3",
"windSpeedDay": "16",
"wind360Night": "315",
"windDirNight": "西北风",
"windScaleNight": "1-3",
"windSpeedNight": "3",
"humidity": "39",
"precip": "0.0",
"pressure": "1021",
"vis": "25",
"cloud": "0",
"uvIndex": "2"
},
{
"fxDate": "2024-12-31",
"sunrise": "07:37",
"sunset": "16:59",
"moonrise": "08:01",
"moonset": "16:57",
"moonPhase": "新月",
"moonPhaseIcon": "800",
"tempMax": "5",
"tempMin": "-4",
"iconDay": "100",
"textDay": "晴",
"iconNight": "150",
"textNight": "晴",
"wind360Day": "225",
"windDirDay": "西南风",
"windScaleDay": "1-3",
"windSpeedDay": "3",
"wind360Night": "0",
"windDirNight": "北风",
"windScaleNight": "1-3",
"windSpeedNight": "3",
"humidity": "36",
"precip": "0.0",
"pressure": "1019",
"vis": "25",
"cloud": "0",
"uvIndex": "2"
},
{
"fxDate": "2025-01-01",
"sunrise": "07:37",
"sunset": "17:00",
"moonrise": "08:49",
"moonset": "18:06",
"moonPhase": "蛾眉月",
"moonPhaseIcon": "801",
"tempMax": "5",
"tempMin": "-5",
"iconDay": "100",
"textDay": "晴",
"iconNight": "150",
"textNight": "晴",
"wind360Day": "45",
"windDirDay": "东北风",
"windScaleDay": "1-3",
"windSpeedDay": "3",
"wind360Night": "0",
"windDirNight": "北风",
"windScaleNight": "1-3",
"windSpeedNight": "16",
"humidity": "39",
"precip": "0.0",
"pressure": "1024",
"vis": "25",
"cloud": "25",
"uvIndex": "2"
},
{
"fxDate": "2025-01-02",
"sunrise": "07:37",
"sunset": "17:01",
"moonrise": "09:28",
"moonset": "19:18",
"moonPhase": "蛾眉月",
"moonPhaseIcon": "801",
"tempMax": "3",
"tempMin": "-8",
"iconDay": "100",
"textDay": "晴",
"iconNight": "150",
"textNight": "晴",
"wind360Day": "315",
"windDirDay": "西北风",
"windScaleDay": "1-3",
"windSpeedDay": "3",
"wind360Night": "270",
"windDirNight": "西风",
"windScaleNight": "1-3",
"windSpeedNight": "3",
"humidity": "21",
"precip": "0.0",
"pressure": "1029",
"vis": "25",
"cloud": "0",
"uvIndex": "2"
},
{
"fxDate": "2025-01-03",
"sunrise": "07:37",
"sunset": "17:02",
"moonrise": "10:00",
"moonset": "20:33",
"moonPhase": "蛾眉月",
"moonPhaseIcon": "801",
"tempMax": "4",
"tempMin": "-7",
"iconDay": "100",
"textDay": "晴",
"iconNight": "151",
"textNight": "多云",
"wind360Day": "225",
"windDirDay": "西南风",
"windScaleDay": "1-3",
"windSpeedDay": "3",
"wind360Night": "0",
"windDirNight": "北风",
"windScaleNight": "1-3",
"windSpeedNight": "3",
"humidity": "20",
"precip": "0.0",
"pressure": "1026",
"vis": "25",
"cloud": "2",
"uvIndex": "2"
},
{
"fxDate": "2025-01-04",
"sunrise": "07:37",
"sunset": "17:03",
"moonrise": "10:29",
"moonset": "21:47",
"moonPhase": "蛾眉月",
"moonPhaseIcon": "801",
"tempMax": "3",
"tempMin": "-6",
"iconDay": "100",
"textDay": "晴",
"iconNight": "150",
"textNight": "晴",
"wind360Day": "225",
"windDirDay": "西南风",
"windScaleDay": "1-3",
"windSpeedDay": "3",
"wind360Night": "270",
"windDirNight": "西风",
"windScaleNight": "1-3",
"windSpeedNight": "3",
"humidity": "23",
"precip": "0.0",
"pressure": "1013",
"vis": "25",
"cloud": "0",
"uvIndex": "2"
}
]
const init = () => {
if (chartRef.current) {
const machart = echarts.init(chartRef.current);
machart.setOption(option(data));
}
}
return (
<div id="temp7day" ref={chartRef}></div>
);
}
export default App;
option配置项
// 处理日期
const dates = data.map(item =>
item.fxDate.slice(5)
);
// 处理天气图标和名称
const imgMap= {
'100':'https://d.scggqx.com/forecast/img/晴.png',
'101':'https://d.scggqx.com/forecast/img/多云.png',
'150':'https://d.scggqx.com/forecast/img/晴.png',
'151':'https://d.scggqx.com/forecast/img/多云.png',
}
const handleDayWeather = data.map(item => {
return {
backgroundColor: {
image: imgMap[item.iconDay]
},
height: 26,
width: 26
}
})
const handleNightWeather = data.map(item => {
return {
backgroundColor: {
image: imgMap[item.iconNight]
},
height: 26,
width: 26
}
})
// 处理温度数据
const maxTemps = data.map(item => item.tempMax);
const minTemps = data.map(item => item.tempMin);
// 处理天气
const weatherText = data.map(item => {
if (item.textDay === item.textNight) {
return item.textDay
} else {
return `${item.textDay}转${item.textNight}`
}
})
return {
grid: {
show: true,
backgroundColor: 'transparent',
opacity: 0.3,
borderWidth: '0',
top: '30%',
bottom: '30%',
left: '7%',
right: '7%'
},
tooltip: {
trigger: 'axis'
},
legend: {
show: false
},
xAxis: [
// 日期0
{
name: '日期',
nameTextStyle: {
fontSize: 0,
},
type: 'category', // 同样是类目轴
boundaryGap: false, // 不留空白
position: 'top', // 位置在顶部
offset: 40, // 与图表上边缘的距离
zlevel: 100, // z轴层级
axisLine: {
show: false // 不显示坐标轴线
},
axisTick: {
show: false // 不显示刻度线
},
axisLabel: {
interval: 0, // 每个标签都显示
formatter: [
'{a|{value}}' // 使用 rich text 格式化标签
].join('\n'), // 换行符
rich: {
a: {
color: '#7EB7D8', // 标签颜色
fontSize: 14 // 字体大小
}
}
},
// nameTextStyle: {
// fontWeight: 'bold', // 字体加粗
// fontSize: 19 // 字体大小
// },
data: dates
},
// 白天图标
{
name: '白天图标',
nameTextStyle: {
fontSize: 0,
},
type: 'category',
boundaryGap: false,//不留空白,数据点从第一个点开始
position: 'top',//将坐标轴放置在图表的顶部。
offset: -20,//设置坐标轴与图表上边缘的距离。
zlevel: 100,//设置层级,使该坐标轴在其他元素之上显示。
axisLine: {
show: false//不显示坐标轴线。
},
axisTick: {
show: false//不显示刻度线。
},
axisLabel: {
interval: 0,
formatter: function (value, index) {
// return `{b|${value}}`;
return '{' + index + '| }\n{b|' + value + '}'
},
rich: {
...handleDayWeather,
b: {
fontSize: 12,
lineHeight: 30,
height: 20
}
}
},
data: ['', '', '', '', '', '', ''] // 占位数据
},
// 夜间图标
{
name: '夜间图标',
nameTextStyle: {
fontSize: 0,
},
type: 'category',
boundaryGap: false,
position: 'bottom',
offset: 10,
zlevel: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
interval: 0,
formatter: function (value, index) {
return '{' + index + '| }\n{b|' + value + '}'
},
//预留rich对象
rich: {
...handleNightWeather,
b: {
fontSize: 12,
lineHeight: 30,
height: 20
}
}
},
data: ['', '', '', '', '', '', ''] // 占位数据
},
// 天气
{
name: '天气',
nameTextStyle: {
fontSize: 0,
},
type: 'category',
boundaryGap: false,
position: 'bottom',
offset: 45,
zlevel: 100,
axisLine: {
show: false
},
axisTick: {
show: false
},
axisLabel: {
interval: 0,
formatter: [
'{a|{value}}'
].join('\n'),
rich: {
a: {
color: '#7EB7D8',
fontSize: 14
}
}
},
data: weatherText
},
],
yAxis: {
type: 'value',
show: false,//控制是否显示纵坐标轴
axisLabel: {//设置纵坐标轴的标签样式。
formatter: '{value} °C',
color: 'white'//设置纵坐标轴标签的颜色为白色
}
},
series: [
{
name: '最高气温',
type: 'line', // 系列类型,这里是折线图
data: maxTemps, // 数据点
symbol: 'emptyCircle', // 数据点的形状
symbolSize: 0, // 数据点的大小
showSymbol: true, // 显示数据点
smooth: true, // 折线是否平滑
itemStyle: { // 数据点样式
normal: {
color: '#F7CC80' // 数据点的颜色
}
},
label: { // 数据标签
show: true, // 是否显示
position: 'top', // 标签位置
formatter: '{c} °C', // 标签内容,这里显示温度
color: '#E3F5FF'
},
lineStyle: { // 折线样式
width: 1, // 线宽
// color: 'white' // 线颜色(这里注释掉了)
},
areaStyle: { // 区域样式(通常用于填充区域)
opacity: 1, // 透明度
color: 'transparent' // 填充颜色(这里是透明的)
}
},
{
name: '最低气温',
type: 'line',
data: minTemps,
symbol: 'emptyCircle', // 数据点的形状
symbolSize: 0, // 数据点的大小
showSymbol: true, // 显示数据点
smooth: true, // 折线是否平滑
itemStyle: { // 数据点样式
normal: {
color: '#089EFE' // 数据点的颜色
}
},
label: {
// 数据标签
show: true, // 是否显示
position: 'bottom', // 标签位置
formatter: '{c} °C', // 标签内容
color: '#E3F5FF',
},
lineStyle: { // 折线样式
width: 1, // 线宽
// color: 'white' // 线颜色
},
areaStyle: { // 区域样式
opacity: 1, // 透明度
color: 'transparent' // 填充颜色(这里是透明的)
}
},
]
}
}
export default option
难点
难点1
X轴上无法之间显示图片,所以利用富文本显示图片,签格式为 '{index| }\n{b|value}',其中 {index| } 用于显示天气图标,{b|value} 用于显示天气名称。 1.
axisLabel: {
interval: 0,
formatter: function (value, index) {
return '{' + index + '| }\n{b|' + value + '}'
},
rich: {
...handleDayWeather,
b: {
fontSize: 12,
lineHeight: 30,
height: 20
}
}
},
data: ['', '', '', '', '', '', ''] // 占位数据
我这里用的是在线图片,如果是本地图片,需要import引入后使用变量,由此引出第二个难点
难点二
和风API天气情况对应的图标有四百多种,如果一个一个用import引入太费劲了,别问我怎么知道,说多了都是泪。
这里可以使用一个快捷方法require.context,篇幅有限,这块放下一章节 [ 动态引入模块-require.content ] 讲解。