websocket+vue+echarts实现实时动态渲染图表
最近遇到一个需求,需要在前端做一个可视化的图表,并且是实时更新的。但echarts不支持图表的实时渲染。只能通过setOption重新设置。我的实现思路是在页面初始化的时候向后端发起一个websocket请求,后端收到连接后将channel保存起来,每次数据更新或隔段时间就轮询这些channel推送数据。...
·
前言
最近遇到一个需求,需要在前端做一个可视化的图表,并且是实时更新的。但echarts不支持图表的实时渲染。只能通过setOption重新设置。我的实现思路是在页面初始化的时候向后端发起一个websocket请求,后端收到连接后将channel保存起来,每次数据更新或隔段时间就轮询这些channel推送数据。
后端
websocket我用的是netty实现的,在handler中的handlerAdded监听add事件后将channel存入service层的channels容器。
/**
* 当有新的连接加入时就将channel添加到指定容器
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
DataChartServiceImpl.putChannel(ctx.channel());
}
service层每隔5s就遍历channels容器,如果客户端还在连接状态就推送消息。
/**
* websocket客户端容器
*/
private static List<Channel> channels = new ArrayList<>();
/**
* 添加客户端
*/
public static void putChannel(Channel channel){
channels.add(channel);
}
/**
* 每隔5s获取一次
* @return void
* @author 黎勇炫
* @create 2022/8/4
* @email 1677685900@qq.com
*/
@Override
@Async
@Scheduled(cron = "0/5 * * * * ?")
public void updateData(){
if(counter.intValue() == 12){
resetData();
}else {
add();
counter.increment();
}
Iterator iterator = channels.iterator();
while (iterator.hasNext()){
Channel channel = (Channel) iterator.next();
if(!channel.isActive()){
iterator.remove();
return;
}
channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(queueData())));
}
}
前端
vue初始化的时候打开websocket连接,同时先向后端controller获取一次数据。因为后端5s传一次数据,要保证视图先渲染出来。每次websocket服务端推送消息时都重新渲染一次ecahrts图表。注意:在websocket中的onmessage 不能直接使用this,需要在外出将this赋值给var _this,在onmessage 方法中操作_this.
mounted(){
this.initWebsocket();
this.initCharts();
},
methods:{
initWebsocket(){
var socket;
var _this = this;
if(window.WebSocket){
// go on
socket = new WebSocket("ws://localhost:8687/connect");
socket.onmessage = function (ev){
var res = JSON.parse(ev.data)
_this.setCharts(res)
}
}
},
initCharts(){
axios.get("/xy/data/queue").then(Response=>{
this.setCharts(Response.data)
})
},
setCharts(data){
let qLinechar = this.$refs.qLinechar
let qPiechar = this.$refs.qPiechar
var myChart = echarts.init(qLinechar);
var myChart2 = echarts.init(qPiechar);
var queueAccDetail = [];
Object.keys(data.queueAccDetail).forEach(function (item){
queueAccDetail.push({name:item,value:data.queueAccDetail[item]})
})
var option = {
title: {
text: '队列容器'
},
tooltip: {
trigger: 'axis'
},
legend: {
data: ['消息堆积','消费成功','消息总数']
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
toolbox: {
feature: {
saveAsImage: {}
}
},
xAxis: {
type: 'category',
boundaryGap: false,
data: data.time
},
yAxis: {
type: 'value'
},
series: [
{
name: '消息堆积',
type: 'line',
stack: '消息堆积',
data: data.accQueueCount
},
{
name: '消费成功',
type: 'line',
stack: '消费成功',
data: data.successQueueCount
},
{
name: '消息总数',
type: 'line',
stack: '消息总数',
data: data.queueTotal
}
]
};
var option2 = {
title: {
text: '堆积详情',
// subtext: 'Fake Data',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [
{
name: 'Access From',
type: 'pie',
radius: '50%',
data: queueAccDetail,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}
]
};
myChart.setOption(option,true);
myChart2.setOption(option2)
}
更多推荐
已为社区贡献3条内容
所有评论(0)