ECharts实现动态曲线(中)

ECharts实现动态曲线(上),模拟数据是在浏览器端生成的。
现在,我们这样做:把模拟数据的生产放到服务器端,浏览器通过Ajax发送请求获取服务端数据。

效果图

在这里插入图片描述

实现

服务器使用了一个定时器。只要服务器一启动,定时器就会开始工作,每隔1000ms生成一次新数据。
浏览器端也使用了一个定时器,点击“开始”按钮,该定时器才会开启,每间隔250ms就会向服务端发送一次请求,以获取新数据来更新图表。

遗留问题

服务端定时器的时间间隔是1000ms,浏览器这边定时器的时间间隔是250ms。忽略因不同步可能导致的时间差,理论上讲,1s内,浏览器能发出4次请求,服务器因此返回4份响应。就像这样,
在这里插入图片描述
现在遇到这么一个问题:在图表动态更新的过程中,切换到了其他标签页,浏览器里定时器的工作受到了影响,即1s内,浏览器只能发出了1次请求,服务器因此只返回1份响应。更糟糕的事情是,曲线上出现断点,丢数据了。不过,切回到原标签页,定时器又恢复正常了。
在这里插入图片描述
想想办法吧。

详细代码

目录结构

在这里插入图片描述

浏览器端
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>动态曲线</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts@4.7.0/dist/echarts.min.js"></script>
    <script src="https://code.jquery.com/jquery-3.5.1.min.js"
            integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
            crossorigin="anonymous">
    </script>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <div id="myChart"></div>
    <div class="container">
        <div class="buttons">
            <div class="button" id="start">开始</div>
            <div class="button" id="end"> 结束</div>
        </div>
    </div>
<script src="./MyButton.js"></script>
<script src="./MyChart.js"></script>
<script src="./index.js"></script>
</body>
</html>
//index.js
initButtons();
const myChart = new MyChart(document.getElementById("myChart"));
myChart.init();

function initButtons(){
    var timer;
    const startBtn = new MyButton(document.querySelector("#start"));
    startBtn.addEventListener("click",function(){
        timer = startTimer();
        startBtn.disable();
    });
    
    const endBtn = new MyButton(document.querySelector("#end"));
    endBtn.addEventListener("click",function(){
        closeTimer(timer);
        startBtn.enable();
    });
}
function startTimer(){
    return timer = setInterval(function(){
        myChart.getDataFromServer();
    },250,myChart);
}
function closeTimer(timer){
    clearInterval(timer)
}

//MyButton.js
(function(win){
    function MyButton(elm){
        this.elm = elm; 
    }
    MyButton.prototype.addEventListener = function(type,handler){
        if(this.elm.addEventListener){
            this.elm.addEventListener(type,handler,false);
        }else {
            this.elm["on"+type] = handler;
        }
    }
    MyButton.prototype.disable = function(){
        this.elm.classList.add("disabled");
    }
    MyButton.prototype.enable = function(){
        this.elm.classList.remove("disabled");
    }
    win.MyButton = MyButton;
}(window));
//MyChart.js
(function(win){
    function MyChart(elm){
        this.elm = elm;
        this.chart = echarts.init(elm); 
        this.chart.gap = 40;
    }
    MyChart.prototype.init = function(){
        const times = [];
        const values = [];
        const gap = this.chart.gap;
        const option = {
            grid:{
                bottom:60,
                top:gap,
                left:gap,
                right:gap,                
            },
            xAxis: {
                type: 'category',
                data:times,
                axisLabel:{
                    rotate:45
                },
                axisTick: {
                    alignWithLabel: true
                },
                name:"时间"
                
            },
            yAxis: {
                type: 'value',
                min:0,
                max:1,
                name:"带宽利用率"
            },
            series: [{
                data:values,
                type: 'line',
                smooth: true
            }],
            tooltip: {
                trigger: 'axis',
                axisPointer: {       
                    type:"line"      
                }
            }
        };
        this.chart.setOption(option);
    }
    MyChart.prototype.update = function(data){
        const {times,values} = data;
        const formatedTimes = times.map(t => formatTime(new Date(t)));
        console.log(formatedTimes);
        this.chart.setOption({
            xAxis:{
                data:formatedTimes
            },
            series:[{
                data:values
            }]
        });  
    }

    MyChart.prototype.getDataFromServer = function(){
        const myChart = this;
        $.ajax({
            type:"get",
            url:"/getData",
            success:function(res){
                myChart.update(res);
            }
        })
    }

    function formatTime(time){
        const hour = time.getHours();
        const min = time.getMinutes();
        const sec = time.getSeconds();
        const h = hour<10 ? "0"+hour : hour;
        const m = min<10  ? "0"+min : min;
        const s = sec<10 ? "0"+sec : sec;
        return h+":"+m+":"+s;
    }

    win.MyChart = MyChart;
}(window))
//index.css
#myChart{
    display:inline-block;
    width:400px;height:200px;
    border:1px solid lightgray;
    border-right:none;
    vertical-align:middle;
}
.container{
    display:inline-block;
    width:80px;height:200px;
    border:1px solid lightgray;
    border-left:none;
    margin:-5px;
    vertical-align:middle;

}
.buttons{
    display:table-cell;
    width:inherit;height: inherit;
    vertical-align: middle;
}
.button{
    font-size:0.75em;
    padding:.3em;
    background-color:rgba(0,0,255,.5);
    border:1px solid transparent;
    border-radius:.5em;
    box-shadow:1px 1px 1px black;
    text-align:center;
    margin:1em;
}
.button:hover{
    cursor:pointer;
    background-color:rgba(0,0,255,1);
    color:white;
}
.disabled{
    background-color:lightgray;
    color:lavender;
    box-shadow:1px 1px 1px lightslategray;
}
.disabled:hover{
    cursor:not-allowed;
    background-color:lightgray;
    color:lavender;
}
服务器端
//server.js
const DataCreator = require("./DataCreator.js");
const dc = new DataCreator();
dc.startTimer();
const express = require("express");
const server = express();
const path = require("path");
server.use(express.static(path.join(__dirname,"src")));
server.get("/getData",function(req,res){
    res.writeHead(200,{"Content-Type":"application/json"});
    const {times,values} = dc;
    res.end(JSON.stringify({
        times,
        values
    }));
});
server.listen(3000,function(){
    console.log("listening on*:3000");
})
//DataCreator.js
function DataCreator(){
    this.dotNum = 10;
    this.interval = 1000;
    this.lastStartTime = undefined;
    this.lastValues = [];
    this.times = [];
    this.values = [];
}
DataCreator.prototype.createTimes = function(){
    let {lastStartTime,dotNum,interval} = this;
    let startTime = lastStartTime?lastStartTime:new Date().getTime();
    this.lastStartTime = startTime + interval;

    let times = [];        
    for(var i=0;i<dotNum;++i){
        var time = new Date(startTime+i*interval);
        times.push(time);
    }
    return times;   
}
DataCreator.prototype.createValues = function(){
    let {lastValues,dotNum} = this;
    let values;
    if(lastValues.length === 0){
        values = [];
        for(var i=0;i<dotNum;++i){
            var value = parseFloat(Math.random().toFixed(2));
            values.push(value);
        }
    }else {
        values = lastValues.slice(1);
        values.push(parseFloat(Math.random().toFixed(2)));
    }
    this.lastValues = values.slice();
    return values;
}
DataCreator.prototype.initData = function(){
    var startTime = new Date().getTime();
    this.times = this.createTimes();
    this.values = this.createValues();   
}
DataCreator.prototype.startTimer = function(){
    this.initData();
    const self = this;
    const {interval} = self;
    const fn = function(){
        self.times = self.createTimes();
        self.values = self.createValues();  
        timer = setTimeout(fn,interval); 
    };
    fn();
}

module.exports = DataCreator;
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值