echarts 风向 风速 曲线首尾相连
数据格式1效果
数据格式2效果
数据格式2 真实数据(每半小时一个数据)效果
vue.js项目该部分源代码:
<div id="windspeedandDirection" style="width:100%"></div> this.initWindspeedandDirection("windspeedandDirection",data);
initWindspeedandDirection(id,data){
let chartElement = document.getElementById(id);
chartElement.style.height = '260px';
let chart = echarts.init(chartElement);
chart.dispose();
chart = echarts.init(chartElement);
//数据格式1
// var data2 = [
// [
// 1483488000000, //时间戳
// 6.19,//风速
// 159.4 //角度
// ],
// [
// 1483574400000,
// 6.19,
// 8.31
// ],
// [
// 1483660800000,
// 3.19,
// 37.77
// ],
// [
// 1483747200000,
// 6.19,
// 340
// ],
// [
// 1483833600000,
// 6.19,
// 79.235
// ],
// [
// 1483920000000,
// 11.19,
// 286.8
// ],
// [
// 1484006400000,
// 17.19,
// 193.71
// ]
// ];
//数据格式2
// var data2 = [
// [
// '2020-9-1 13:15:31', //年月日时分秒
// 6.19,//风速
// 159.4 //角度
// ],
// [
// '2020-9-1 14:15:31',
// 6.19,
// 8.31
// ],
// [
// '2020-9-1 15:15:31',
// 3.19,
// 37.77
// ],
// [
// '2020-9-1 16:15:31',
// 6.19,
// 340
// ],
// [
// '2020-9-1 17:15:31',
// 6.19,
// 79.235
// ],
// [
// '2020-9-1 18:15:31',
// 11.19,
// 286.8
// ],
// [
// '2020-9-1 19:15:31',
// 17.19,
// 193.71
// ]
// ];
//只显示小时和分钟数据 方式1 同时设置xAxis type: 'category'
let data2 =data.map(function (item) {
return [item['TIMESTAMP'],item['WS_Avg'],item['WD']];
});
//只显示小时和分钟数据 方式2 同时设置xAxis type: 'category',问题:formatTime只返回小时和分钟部分,但X轴重复会出现曲线首尾相连。
// let data2 =data.map(function (item) {
// return [util.formatTime (new Date(item['TIMESTAMP'])),item['WS_Avg'],item['WD']];
// });
//只显示小时和分钟数据 方式3 同时设置xAxis type: 'time', tooltip-formatter方法,缺点X轴设置为time类型,时间间隔无法控制。
console.log(id,data,data2);
//console.log('data',data)
//console.log('data2',data2)
//dims对象保存数组的维度,方便从data数组中取数据
var dims = {
time: 0, //时间的维度是0
windSpeed: 1,//风速的维度是1
R: 2 //角度(0-360)的维度是2
};
let that=this;
var option = {
tooltip: {
trigger: 'axis',
// formatter: function (params) { //时间戳转年月日
// return [
// echarts.format.formatTime('yyyy-MM-dd', params[0].value[dims.time])
// + ' ' + echarts.format.formatTime('hh:mm', params[0].value[dims.time]),
// '风速:' + params[0].value[dims.windSpeed],
// '风向:' + params[0].value[dims.R]
// ].join('<br>');
// }
formatter: function (params) {
return [
params[0].value[dims.time],
'风速(m/s):' + params[0].value[dims.windSpeed],
'风向(度):' + params[0].value[dims.R],
'风向:' + util.formatWindDirection(params[0].value[dims.R])
].join('<br>');
}
},
grid: {
top: 50,
left: 45,
right: '4%',
bottom: '2%',
containLabel: true
},
xAxis: {
/*
ecnarts文档-配置项: xAxis. type
坐标轴类型。
可选:
'value' 数值轴,适用于连续数据。
'category' 类目轴,适用于离散的类目数据。为该类型时类目数据可自动从 series.data 或 dataset.source 中取,或者可通过 xAxis.data 设置类目数据。
'time' 时间轴,适用于连续的时序数据,与数值轴相比时间轴带有时间的格式化,在刻度计算上也有所不同,例如会根据跨度的范围来决定使用月,星期,日还是小时范围的刻度。
'log' 对数轴。适用于对数数据。
*/
//type: 'value',
type: 'category',
//type: 'time',
//data: xAxisData,
splitLine:{
show:false//去掉网格中的垂直线
},
boundaryGap:false,
axisLabel:{
//interval: 0, //坐标轴刻度标签的显示间隔.设置成 0 强制显示所有标签。设置为 1,隔一个标签显示一个标签。
//rotate: 45,//倾斜度 -90 至 90 默认为0
// textStyle: {
// fontWeight: "bold", //加粗
// color: "#000000" //黑色
// },
formatter:function(date1,index){//在这里把时间转化为小时和分钟,就能解决曲线首尾相连问题
//console.log('formatter',date1,index);
let date=null;
if (date1) {
if (typeof (date1) === 'string') {
date = new Date(date1.replace(/-/g, '/'));
}else{
date = new Date(date1);
}
// const y = date.getFullYear();
// let m = date.getMonth() + 1;
// m = m < 10 ? '0' + m : m;
// let d = date.getDate();
// d = d < 10 ? ('0' + d) : d;
let h = date.getHours();
h = h < 10 ? '0' + h : h;
let mi = date.getMinutes();
mi = mi < 10 ? '0' + mi : mi;
return h+ ':' + mi;
} else {
return null;
}
}
}
// axisPointer:{
// label:{
// formatter: function(data){
// console.log('xAxis',data)
// return "10";
// }
// }
// }
},
yAxis: [{
name: '风速(m/s)',
}],
series: [
{
/*echarts文档-配置项: series-custom
custom 系列需要开发者自己提供图形渲染的逻辑。这个渲染逻辑一般命名为 renderItem
*/
type: 'custom',
renderItem: this.renderArrow,
/*echarts文档-配置项:series-line.encode
可以定义 data 的哪个维度被编码成什么。比如:
encode: {
x: [3, 1, 5], // 表示维度 3、1、5 映射到 x 轴。
y: 2, // 表示维度 2 映射到 y 轴。
tooltip: [3, 2, 4] // 表示维度 3、2、4 会在 tooltip 中显示。
}
*/
encode: {
x: dims.time,
y: dims.windSpeed
},
data: data2,
/*
series-custom. z
自定义图组件的所有图形的z值。控制图形的前后顺序。z值小的图形会被z值大的图形覆盖。
z相比zlevel优先级更低,而且不会创建新的 Canvas。
*/
z: 10
},
{
type: 'line',
symbol: 'none', //不显示点
smooth: true, //这句就是让曲线变平滑的
connectNulls: true,//断点连接
encode: {
x: dims.time,
y: dims.windSpeed
},
lineStyle: {
normal: {
color: 'rgb(148, 192, 90)',
//type: 'dotted'
}
},
data: data2,
z: 3
}]
};
//console.log('option',option);
chart.setOption(option);
chart.resize();
this[id] = chart;
},
onresizeAir(){ let idArr=['windspeedandDirection']; for(let i=0;i<idArr.length;i++){ let id=idArr[i]; let chartElement = document.getElementById(id); chartElement.style.height = (window.innerHeight -139)/3+'px'; //window.innerHeight浏览器高度 this.resizeChart(this[id]); // console.log('ceshi1',(window.innerHeight -123)/3); // console.log('chartElement',chartElement) // console.log('that[id]',that[id]) } }, mounted () { let that=this; setTimeout(function(){ that.onresizeAir(); }, 400); window.addEventListener('resize', () => { that.onresizeAir(); }, false) },
renderArrow(param, api) { /* echarts文档-配置项: series-custom. renderItem 对于 data 中的每个数据项(为方便描述,这里称为 dataItem),会调用此 renderItem 函数。 renderItem 函数提供了两个参数: params:包含了当前数据信息和坐标系的信息。 api:是一些开发者可调用的方法集合。 renderItem 函数须返回根据此 dataItem 绘制出的图形元素的定义信息,参见 renderItem.return。 一般来说,renderItem 函数的主要逻辑,是将 dataItem 里的值映射到坐标系上的图形元素。这一般需要用到 renderItem.arguments.api 中的两个函数: api.value(...),意思是取出 dataItem 中的数值。例如 api.value(0) 表示取出当前 dataItem 中第一个维度的数值。 api.coord(...),意思是进行坐标转换计算。例如 var point = api.coord([api.value(0), api.value(1)]) 表示 dataItem 中的数值转换成坐标系上的点。 有时候还需要用到 api.size(...) 函数,表示得到坐标系上一段数值范围对应的长度。 返回值中样式的设置可以使用 api.style(...) 函数,他能得到 series.itemStyle 中定义的样式信息,以及视觉映射的样式信息。也可以用这种方式覆盖这些样式信息:api.style({fill: 'green', stroke: 'yellow'})。 */ //数据参数顺序 var dims = { time: 0, windSpeed: 1, R: 2 }; var arrowSize = 12; var point = api.coord([ api.value(dims.time), api.value(dims.windSpeed) ]); let rotationData= api.value(dims.R); // console.log('param',param); // console.log('api',api); // console.log('point',point); let obj={ type: 'path', shape: { pathData: 'M 146.5 230 L 141.298 239.011 L 146.5 219.595 L 151.702 239.011 Z',//绘制图形 //'M31 16l-15-15v9h-26v12h26v9z', x: -arrowSize / 2, y: -arrowSize / 2, width: arrowSize, height: arrowSize }, rotation: -rotationData*(Math.PI/180), //echarts文档-配置项: series-custom.renderItem.return_path. rotation //旋转(rotation):默认值是 0。表示旋转的弧度值。正值表示逆时针旋转。 //1) 角度转换为弧度公式:弧度=角度*(π /180 ) //2)弧度转换为角度公式: 角度=弧度*(180/π) //平移(position):默认值是 [0, 0]。表示 [横向平移的距离, 纵向平移的距离]。右和下为正值。 position: point, style: api.style({ stroke: 'rgb(102, 0, 204)',//图形颜色 lineWidth: 1 }) }; //console.log('obj',obj); return obj },
一些格式转换方法(时间转换、风速转风力、风向度数转文字、四舍五入保留2位小数)
util.formatDate = function (date) { if (date) { if (typeof (date) === 'string') { date = new Date(date.replace(/-/g, '/')); } const y = date.getFullYear(); let m = date.getMonth() + 1; m = m < 10 ? '0' + m : m; let d = date.getDate(); d = d < 10 ? ('0' + d) : d; return y + '-' + m + '-' + d; } else { return null; } }; util.formatDateTime = function (date) { //console.log('formatDateTime',date) if (date) { if (typeof (date) === 'string') { date = new Date(date.replace(/-/g, '/')); } const y = date.getFullYear(); let m = date.getMonth() + 1; m = m < 10 ? '0' + m : m; let d = date.getDate(); d = d < 10 ? ('0' + d) : d; let h = date.getHours(); h = h < 10 ? '0' + h : h; let mi = date.getMinutes(); mi = mi < 10 ? '0' + mi : mi; return y + '-' + m + '-' + d + ' ' + h + ':' + mi; } else { return null; } }; util.formatHourMinutes = function (date) { if (date) { if (typeof (date) === 'string') { date = new Date(date.replace(/-/g, '/')); } const y = date.getFullYear(); let m = date.getMonth() + 1; m = m < 10 ? '0' + m : m; let d = date.getDate(); d = d < 10 ? ('0' + d) : d; let h = date.getHours(); h = h < 10 ? '0' + h : h; let mi = date.getMinutes(); mi = mi < 10 ? '0' + mi : mi; return h + ':' + mi; } else { return null; } }; util.formatTime = function (date) { if (date) { if (typeof (date) === 'string') { date = new Date(date.replace(/-/g, '/')); } const y = date.getFullYear(); let m = date.getMonth() + 1; m = m < 10 ? '0' + m : m; let d = date.getDate(); d = d < 10 ? ('0' + d) : d; let h = date.getHours(); h = h < 10 ? '0' + h : h; let mi = date.getMinutes(); mi = mi < 10 ? '0' + mi : mi; return h + ':' + mi; } else { return null; } }; util.formatTwoDecimalPlaces= function (val) { if (val==undefined||val==null||typeof (val) !== 'number'){ return null; } let v2=100; return Math.round(val * v2) / v2; }; /** * 根据日期字符串获取星期几 * @param dateString 日期字符串(如:2020-05-02) * @returns {String|Null} */ util.formatWeek= function(dateString) { //dateString="2020-11-27 10:10:03.378"; if(dateString){ let date = new Date(dateString); //console.log('getWeek',date,dateString, date.getFullYear(),date.getMonth(),date.getDate(),date.getHours(),date.getMinutes(),date.getSeconds(),date.getMilliseconds(),date.getDay()) return "周" + "日一二三四五六".charAt(date.getDay()); }else{ return null; } }; /** * 风向 角度转文字 * @param data 向角(如:1.34) * @returns {Number} */ util.formatWindDirection= function(data) { if(data){ let val =parseInt((data/22.5)+0.5) //let arr= ["N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"] let arr2=["北","东北偏北","东北","东北偏东","东","东南偏东", "东南", "东南偏南","南","西南偏南","西南","西南偏西","西","西北偏西","西北","西北偏北"] let name= arr2[(val % 16)]; //console.log('name',name); return name; }else{ return null; } }; /** * 风力 m/s转等级 * @param data 向角(如:1.34) * @returns {Number} */ util.formatWindGrades= function(data) { if(data){ let arr=["无风","软风","轻风","微风","和风","清风","强风","劲风(疾风)","大风","烈风","狂风","暴风","台风","台风","强台风","强台风","超强台风","超强台风","超强台风","超强台风"]; let gradeArr=[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18]; let arr2=[0.3,1.6,3.4,5.5,8.0,10.8,13.9,17.2,20.8,24.5,28.5,32.7,37.9,41.5,46.2,51.0,56.1,61.3,69.4]; let name= ""; let grade=""; if(data<arr2[0]){ name=arr[0]; grade=gradeArr[0]; }else if(data<arr2[1]){ name=arr[1]; grade=gradeArr[1]; }else if(data<arr2[2]){ name=arr[2]; grade=gradeArr[2]; }else if(data<arr2[3]){ name=arr[3]; grade=gradeArr[3]; }else if(data<arr2[4]){ name=arr[4]; grade=gradeArr[4]; }else if(data<arr2[5]){ name=arr[5]; grade=gradeArr[5]; }else if(data<arr2[6]){ name=arr[6]; grade=gradeArr[6]; }else if(data<arr2[7]){ name=arr[7]; grade=gradeArr[7]; }else if(data<arr2[8]){ name=arr[8]; grade=gradeArr[8]; }else if(data<arr2[9]){ name=arr[9]; grade=gradeArr[9]; }else if(data<arr2[10]){ name=arr[10]; grade=gradeArr[10]; }else if(data<arr2[11]){ name=arr[11]; grade=gradeArr[11]; }else if(data<arr2[12]){ name=arr[12]; grade=gradeArr[12]; }else if(data<arr2[13]){ name=arr[13]; grade=gradeArr[13]; }else if(data<arr2[14]){ name=arr[14]; grade=gradeArr[14]; }else if(data<arr2[15]){ name=arr[15]; grade=gradeArr[15]; }else if(data<arr2[16]){ name=arr[16]; grade=gradeArr[16]; }else if(data>=arr2[17]){ name=arr[17]; grade=gradeArr[17]; } //console.log('name',name); return {name:name,grade:grade}; }else{ return null; } }; export default util;
参考来源:
https://www.cnblogs.com/w2011/p/11277147.html
从该文档知道怎么做,但很多地方没注释不明白意思。
http://www.weather.com.cn/weather1d/101121201.shtml
中国天气网 F12 获取绘制箭头图形的编码和颜色
如果想显示风力等级曲线,可以用formatWindGrades方法 把风速转换为风力等级
树立目标,保持活力,gogogo!