#问题:
后端发给前端二进制数据流,前端如何解析,实时写入echarts折线图,接下来我们看下面解析和用到的前端技术。
一, 需要了解的内容
1,大家都知道二进制的字节是(1111 1111)是一个字节,那么转换成16进制就是(ff)。
2,我解析的二进制数据流的数据格式是
(ff ff ff ff 0x xx xx xx 1x xx xx xx …… 7x xx xx xx,0x xx xx xx……循环到1028个字节),
描述:
1>,ff ff ff ff是包头是四个字节,每1028个字节中有一个包头,实际数据是1024加包头是1028。
2>,0x到7x是一组数据是8个通道的数据,(除0通道以外,0x这一小组数据有效数据是第2个字节和第3个字节,
也就是说,第1个字节和4个字节是无用数据),每组数据的每四个字节的是一小组,一小组的第一个字节
是无用数据也就是1x,有用的数据是xx xx xx,
3,正常一个数据包都是1024个字节,但是此数据的长度是fpga自定义的1028个字节为一包数据,关于fpga是啥不明白可以百度,这里不做过多的描述。
不明白的可以看图
二,我们来看下方的解析数据
描述:如何解析二进制码流
1,先使用$axios获取后端的接口数据使用try判断你当前发送的数据是arraybuffer还是json的数据,因为我们要接收俩种数据类型的数据。
2,接下来我们使用DataView来获取二进制数据流,如不知道DataView是什么请看此链接
(https://blog.csdn.net/qiqingjin/article/details/51816227)
3,使用for循环算出后端一共给我们多少包数据,在使用一个for循环去掉每包数据的前四个字节的数据。因为我们要已四个字节为
一组所以所以我们要使用getuint32,算出来的就是四字节一小组数据,然后我们push到提取创建好的二维数组中。
4,var定义的h,m,s,是echarts中的x轴的数据,判断that.form.timee.length>=6000是保证图中可以放下6000个点,超过6000就从
图中左侧开始删除,保证图中最多6000个。
相应的代码
webSocketClientOnopen(now) {
var that = this
this.$axios({// ajax
url:'/send_fpga_data',
method:'post',
responseType:'arraybuffer',
})
.then(function (response) {
try{ //执行代码
let enc = new TextDecoder('utf-8')
var tmp = JSON.parse(enc.decode(new Uint8Array(response.data)))
if(tmp.code == 20000){
that.form.Click_on_the_state = true
that.$message('关闭成功!')
clearInterval(that.clearTimeSet); //关闭定时器
}
}
catch(err){ //处理错误
console.log(response)
const view1 = new DataView(response.data);
for(var i=0;i<view1.byteLength/1028;i++){
for(var p=1;p<(1028/4);p++){
var algodata = view1.getUint32(i*1028+p*4)
//console.log(algodata.toString(16))
that.form.channel[(p-1)%8].push(that.analytic_function(((p-1)%8), algodata))
var myDate = new Date();
var h=myDate.getHours();
var m=myDate.getMinutes();
var s=myDate.getSeconds();
var now = h+":"+m+"."+s
if(that.form.channel[that.form.select_aisle].length == that.form.timee.length){
console.log('数据正在写入中...')
}else{
that.form.timee.push(now)
that.set_option();
if (that.form.timee.length>=6000){
that.form.timee.shift()
that.form.channel[0].shift()
that.form.channel[1].shift()
that.form.channel[2].shift()
that.form.channel[3].shift()
that.form.channel[4].shift()
that.form.channel[5].shift()
that.form.channel[6].shift()
that.form.channel[7].shift()
}
}
}
}
}
})
.catch(function (error) {
console.log(error);
})
},
三,接下来我们创建二维数组
描述:
先创建一个数组,初始化的时候我们在这个数组中循环插入8个数组,也是8个通道的y轴数据。
相应的代码
<script>
const echarts = require('echarts');
export default{
data () {
//watch
return {
form:{
channel:[],//二维数组
},
};
},
mounted(){ //在这发起后端请求,拿回数据,配合路由钩子做一些事情(dom渲染完成 组件挂载完成 )
this.initCharts();
for(var chn=0;chn<8;chn++){
this.form.channel[chn] = new Array()
}
},
}
四,解析完数据,通过算法得到需要的数据
描述:
1,下图中if判断==0是判断的二维数组中第一个数组,其他的数组都走的是else,因为0通道的数据比较特殊,需要单独解析和算。
2,0通道我们拿到数据以后吧四字节数据像左移8,像右边移16就可以去掉第一个字节和第4个字节,我们拿到的就是有效数据了。
3,根据算法,数据*5/2^15就是我们要的值,保留4位小数,把他写入echarts。
4,其他通道同样的道理,不做过多描述。
5,Set_option函数每次只展示一个通道的数据,根据this.form.select_aisle实时获取数据变化去实现的,也是吧数据实时写入图中的函数。
相应代码
methods: {//methods中一般都是定义的需要事件触发的一些函数。每次只要触发事件,就会执行对应的方法
analytic_function(chn,algodata){
var price;
if(chn==0){
algodata = algodata<<8
//console.log(algodata.toString(16))
var right_shift_1 = algodata>>16
var channel_algorithm1 = right_shift_1*5
var calculate_square1 = Math.pow(2,15)
var answer1 = channel_algorithm1/calculate_square1
price = answer1.toFixed(4)
}else{
var true_data2 = algodata<<8
var right_shift_2 = true_data2>>8
//console.log(right_shift_2.toString(16))
var channel_algorithm2 = right_shift_2*5
var calculate_square2 = Math.pow(2,23)
var answer2 = channel_algorithm2/calculate_square2
price =answer2.toFixed(4)
}
return price
},
set_option(){
var Minus_one = parseInt(this.form.select_aisle)
var Minus_one_data = Minus_one+1
// console.log(Minus_one_data)
this.myChart.setOption({
xAxis: {
data : this.form.timee,
},
series: [
{
name:'通道'+ Minus_one_data,
data:this.form.channel[this.form.select_aisle],//.splice(0,1000)
},
]
});
},
}
五,获取页面数据发送后端,启动定时器
描述:
1,下图是页面输入需要打包数据的接口函数,点击查看波形图启动定时器,定时像后端获取数据,直到你获取到你
所需要的全部包数停下来。
相应代码
look_at_the_picture(){
var that =this
if(this.form.package!='' && this.form.package<=8000 && this.form.package>0){
this.data_package = {"packet_num":parseInt(this.form.package)}
this.$axios.post("/set_packet_num",this.data_package)
.then(function(response){
// console.log(response);
if(response.data.code==20000){
that.form.timee = []//第二次请求,清空二维数组,重新加载
that.form.channel[0] = []
that.form.channel[1] = []
that.form.channel[2] = []
that.form.channel[3] = []
that.form.channel[4] = []
that.form.channel[5] = []
that.form.channel[6] = []
that.form.channel[7] = []
that.myChart.dispose();
that.initCharts()
if (that.form.Click_on_the_state == true) {
that.form.Click_on_the_state = false
that.$message('点击成功!')
that.clearTimeSet=setInterval(() => {//定时器
that.webSocketClientOnopen();
}, 3000);
}else{
that.$message('点击无效!')
}
}else{
that.$message({type: 'error',message: '配置失败!'});
}
})
.catch(function (error) {
console.log(error);
})
}else{
this.$message({type: 'error',message: '输入无效!'});
}
},
六,echarts折线图代码
下图是折线图代码,不做描述。
initCharts () {
window.addEventListener("resize",()=>{
this.myChart.resize();
})
this.myChart = echarts.init(document.getElementById("map"))
this.option = {
// title: { text: '在Vue中使用' },
grid:{//调试折线图,是否撑满容器
top:"50px",
left:"60px",
right:"60px",
bottom:"40px"
},
tooltip: {
trigger:'axis'
},
legend:{
data:['通道1','通道2','通道3','通道4','通道5','通道6','通道7','通道8']
},
toolbox: {//折线图右上角的放大缩小等等功能
show: true,
feature: {
dataZoom: {
yAxisIndex: 'none'
},
dataView: {readOnly: false},
magicType: {type: ['line', 'bar']},
restore: {},
saveAsImage: {}
}
},
xAxis: {
type : 'category',
boundaryGap : false,
// axisLabel:{
// interval:100, //加入axisLabel字段,interval后面加你想要间隔的个数
// },
show:false,
data : this.form.timee,
},
yAxis: {
type : 'value',
splitLine: {//去除网格线
show: false ,
},
axisTick: {
show: true,
},
name: '(幅值)'
},
tooltip: {
trigger: 'axis',
position: function (pt) {
return [pt[0], '10%'];
}
},
dataZoom: [
{
type: 'inside',
start: 100,
end: 80
},
{
start: 0,
end: 10
}
],
series: [
{
name:'通道'+this.form.select_aisle,
type:'line',
stack: '总量',
smooth: true,//调试曲线
//sampling: 'average',//降采样策略
symbol:'none',
data:this.form.channel[this.form.select_aisle],
markLine: {
precision:4,//调试最大值最小值等,保留几位小数
data: [
{type: 'average', name: '偏置'},
{type: 'max',name:'最大值'},
{type: 'min',name:'最小值'},
]
}
},
]
};
//this.option &&
this.myChart.setOption(this.option)
}
六,页面,和正确波形图
1,页面
2,正确波形图
完结,不喜勿喷!