highcharts 数据量过大,几万条数据,怎么解决显示问题呢?实例剖析异步加载 170 万条数据

hightcharts使用的范围应该很广了,但是因为他的渲染方式是svg,当数据量达到成千上万条的时候,那么问题就来了,浏览器会卡死,渲染不出来。这个问题官方已经给了解决实例。但是很少被人注意到,我遇到这个问题的时候,网上查了半天才发现。
下面实例总结一下,先说一下Highcharts、Highstock的区别:

Highcharts的数据量理论是万级,默认是1000,可以通过 turboThreshold 来指定。
Highstock的数据量可以达到十万甚至是百万级,通过异步加载等优化手段可以轻松胜任百万数据。

html代码

<!DOCTYPE HTML>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>DPUv2 Profiler</title>
    <script src="./jquery-3.1.1.min.js"></script>
    <script src="./highstock.js"></script>
    <script src="./modules/xrange.js"></script>
    <script src="./modules/exporting.js"></script>
    <style type="text/css">
     #container {
       width: 100%;
       height: 600px;
       margin: 1em auto;
     }
    </style>
  </head>
  <body>
    <div id="container"></div>
  </body>
 </html>

js部分

     var chartData = []//所有数据
        var options = {
            chart: {
               type: 'xrange',
               renderTo: "container",
               zoomType: 'x'
            },
            title: {
               text: 'DPUv2 Profiler'
            },
            yAxis: {
                title: {
                   text: ''
                },
                categories: ['LOAD', 'SAVE', 'CONV', 'MISC'],
                reversed: true
            },
            xAxis : {
                    events : {
                            afterSetExtremes : afterSetExtremes
                    }
            },
            navigator: {
                adaptToUpdatedData: false,
                enabled: true,
                height: 120,
                xAxis: {
                    visible: false
                },
                yAxis: {
                    reversed: true,
                    visible: false
                },
                series: {
                    type: 'xrange',
                    dataGrouping: {
                        enabled: true
                    }
                }
            },
            keyboardNavigation: {
                mode: 'normal'
            },
            scrollbar: {
                enabled: true
            },
            rangeSelector: {
                enabled: false
            },
            tooltip:{
                headerFormat: '<small>partialFill</small>: ',
                pointFormatter: function(){
                    let html = '<b>' + this.partialFill + '</b><br/>'
                    html += "currentLine: "+this.sort
                    for(key in this.info){
                        html += '<br/><p><span>' + key + ': </span>' +
                        '<span style="text-align: right"><b>' + this.info[key] + '</b></span></p><br/>'
                    }
                    return  html
                },
                valueDecimals: 2
            },
            series: [{
                turboThreshold: 0,
                name: '',
                borderColor: '#E0E0E0',
                pointWidth: 30,
                pointPadding: 0,
                showInLegend: false,
                allowPointSelect: true,
                showInNavigator: true,
                    data: [{}],
                    dataLabels: {
                        enabled: false
                    },
                    states: {
                        select: {
                            color: '#888888'
                        }
                    }
            }]
        }
        function dataHandle(data){
            var dest = []
            data.forEach((item,index)=>{
                var color
                switch(item.name) {
                 case 'LOAD':
                   color = '#90EE90'
                   break
                 case 'SAVE':
                   color = '#FF69B4'
                   break
                 case 'END':
                   color = '#000000'
                   break
                 case 'CONVINIT':
                   color = '#BA55D3'
                   break
                 case 'CONV':
                   color = '#6495ED'
                   break
                 case 'POOL':
                   color = '#FFD700'
                   break
                 case 'ELEWINIT':
                   color = '#FFA07A'
                   break
                 case 'ELEW':
                   color = '#FF6347'
                   break
                 default:
                   color = "#999999"
                }
                dest.push({
                     x: parseInt(item.x),
                     x2: parseInt(item.x2),
                     y: parseInt(item.y),
                     name: item.name,
                     color: color,
                     info: item.info,
                     partialFill: 1 - parseFloat(item.efficiency),
                     dpd: item.dpd,
                     id: index + 1,
                     sort:item.sort
               })
            })
            return dest
        }
        function afterSetExtremes(e) {
            var chart = $('#container').highcharts()
            chart.showLoading('Loading data from server...')
            var dest = []
            chartData.forEach((item,index)=>{
                if((item.x2 >= (e.min)) && (item.x <= e.max)){
                    dest.push(item)
                }
            })
            console.log(dest)
            var data = dataHandle(dest)
            chart.series[0].setData(data)
            chart.hideLoading()
        }
        function GetQueryString(name) {
             var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
             var r = window.location.search.substr(1).match(reg);
                  if(r!=null)return  unescape(r[2]); return null;
        }
        function JsonCount(jsonArr){
            var JsonOBj = []
            var tempArr = []//记录分类
            JsonOBj.all = jsonArr.length
            jsonArr.forEach((item,index)=>{
                jsonArr[index].sort = index + 1 //给原始数据加个序号
                if(tempArr.indexOf(item.name) < 0){
                    //还没这项
                    JsonOBj[item.name] = 1
                    tempArr.push(item.name)
                }else{
                    JsonOBj[item.name] ++
                }
            })
            return JsonOBj
        }
        function renderCount(countData){
            let html = ""
            console.log(countData)
            for(var key in countData){
                html += "<li><b>"+key+": </b>"+countData[key]+"</span></li>"
            }
            $(".info_list").html(html)
        }
        $(function(){
            var filename = GetQueryString('file')
            $.getJSON('/gantt/'+filename, function(data) {
                chartData = data
                var countData = JsonCount(chartData)
                renderCount(countData)
                var loadData = dataHandle(data.slice(0,200))
                options.series[0].data = loadData
                new Highcharts.Chart(options)
            })
        })

根据官网demo改造的,原文链接https://www.hcharts.cn/demo/highstock/lazy-loading
其中dataHandle是把我们的json数据处理成highcharts期望渲染的数据结构。
核心原理就是首次渲染的时候,先渲染了数据的前200条。区间选取的时候会触发afterSetExtreme()函数,我们根据e.min&&e.max过滤我们的数据然后重新渲染。

未经允许不得转载:莫小奈博客 » highcharts 数据量过大,几万条数据,怎么解决显示问题呢?实例剖析异步加载 170 万条数据

评论 0

评论前必须登录!

登陆 注册