zoukankan      html  css  js  c++  java
  • 使用 amcharts 和 highcharts 绘制多曲线时间趋势图的通用方法


           工作中用到, 这里分享一下。 可以使用 amcharts 和 highcharts 在同一坐标中绘制多个对比曲线图。 当然, 对图形没有过多装饰, 可以参考 API 文档:

           highcharts:   Highcharts API

           amcharts:     amcharts API


          0.  说明

          amcharts 与 highcharts 对于数据格式的要求是不一样的。 amcharts 只需要一个 对象数组 [{'x': 1, 'y': 2, 'z': 3}, {'x':2, 'y': 4, 'z': 6}], 并指明 x ,y 轴的字段名,其它的就交给 amcharts 了; 而 highcharts 则需要对每个曲线图定义好二维数组 ,  [[1,2], [2,4]] , [[1,3], [2,6]] ; 如果要使用对象数组返回格式, 就需要进行数据抽取和重组, 以符合 highchart 的要求。

           由于 javascript 所使用的标准数据格式是 JSON, 因此, 可以非常方便地进行数据拼接和组合。 也就是说, 如果要在同一坐标中绘制多个曲线图, 只需要定义一个数组, 将多个曲线图的数据加入数组即可。

           实现中, 有五点需要重点说明:

           a.  时间字段。 由于不同的API 返回的JSON数据中,时间的字段名不一定相同(比如有的为 time, 有的为 timestamp), 并且时间的格式有所不同(比如有的为字符串, 有的为时间戳), 为了追求灵活性, 需要使用一个日期转换函数 convertDate(chartData, timeStampFieldName, dateConvertFunc) 来统一处理。 这里统一转换为 javascript timestamp 再转化为 Date 类型, 可以兼容 Firefox 和 Chrome .  当然, 具体转换为什么类型, 要视采取的库支持决定。

           b.  返回数据的格式, 主要以对象数组为主;

           c.   由于要绘制任意多个曲线图, 这里也需要考虑到灵活性, 利用了 JSON 格式的灵活性, 采用循环方式加入多个曲线的配置项来实现;

           d.  在实现中,尽可能基于已有库提供相同的使用接口, 这样, 就可以在多个选择中自由地切换; 

           e.  简单的框架性处理: 通常显示多图时, 一般会显示小图, 然后点击后显示大图。 这里, 点击小图后显示大图,最好做成框架中的处理, 客户端使用不必操心这种事情,也避免了将类似的代码分布在系统的各处。即尽量遵循“一个事实”的设计原则。


         1.  返回数据格式       

    {"result":{"msg":null,"code":200,"data":[{"__source__":"10.201.20.35","__time__":"1380446527","blocked":"0","plist":"1517","runq":"0","ldavg_1":"2.34","ldavg_5":"1.56","ldavg_15":"1.43","time":"Sun Sep 29 17:22:07 2013"},{"__source__":"10.201.20.35","__time__":"1380446587","blocked":"0","plist":"1524","runq":"5","ldavg_1":"2.38","ldavg_5":"1.69","ldavg_15":"1.48","time":"Sun Sep 29 17:23:07 2013"},{"__source__":"10.201.20.35","__time__":"1380446647","blocked":"0","plist":"1523","runq":"3","ldavg_1":"1.51","ldavg_5":"1.56","ldavg_15":"1.45","time":"Sun Sep 29 17:24:07 2013"}],"success":true}}

          2. HTML DIV    

    <body>
            <div id="perfcharts">
                <div id="Loadperfchartdiv" style="100%; height:400px;" class="chartdiv"></div>
            </div>
        </body>

          3.  使用 amcharts 绘制:  

          需要导入

    <script src="../amcharts.js" type="text/javascript"></script>   
    <script src="../jquery-1.10.1.min.js" type="text/javascript"></script>
    <script src="../drawchart.js" type="text/javascript"></script>

         drawchart.js 是编写的基于 amcharts 的在同一坐标中绘制多图形的客户端接口:

    /**
     * 使用 amcharts 绘制时间趋势曲线图
     * 
     * generateChart:
     *     chartDiv  绘图所需要的 DIV 区域名称;
     *     chartData 绘图所需要的数据
     *     chartConfig 绘图的全局配置对象
     *     lineConfigArray  每个曲线图的配置对象(配置Y轴)
     * 
     */
    var globalChart = null, globalChartData = null;
    function generateChart(chartDiv, chartData, chartConfig, lineConfigArray) {
            console.log('begin draw chart: ' + getNow());
            // SERIAL CHART
            var chart = new AmCharts.AmSerialChart();
            globalChart = chart;
            globalChartData = chartData;
            chart.pathToImages = "../resources/images/amcharts2/";
            chart.zoomOutButton = {
                backgroundColor: '#000000',
                backgroundAlpha: 0.15
            };
            chart.dataProvider = chartData;
            chart.categoryField = "timeStamp";
    
            // data updated event will be fired when chart is first displayed,
            // also when data will be updated. We'll use it to set some
            // initial zoom
            chart.addListener("dataUpdated", zoomChart);
           
            // AXES
            // Category
            var categoryAxis = chart.categoryAxis;
            categoryAxis.parseDates = true; // in order char to understand dates, we should set parseDates to true
            categoryAxis.minPeriod = "mm";  // as we have data with minute interval, we have to set "mm" here.             
            categoryAxis.gridAlpha = 0.07;
            categoryAxis.axisColor = "#DADADA";
            categoryAxis.labelFunction = function(valueText, date, categoryAxis) {
                var MM = date.getMonth()+1;
                var dd = date.getDate();
                var hh = date.getHours();
                if(hh<10) hh = '0' + hh;
                var mm = date.getMinutes();
                if(mm<10) mm = '0' + mm;
                var ss = date.getSeconds();
                return MM+'-'+dd+' '+hh+':'+mm;
            }
            
            // Value
            var valueAxis = new AmCharts.ValueAxis();
            valueAxis.gridAlpha = 0.07;
            valueAxis.title = chartConfig.title;
            chart.addValueAxis(valueAxis);
    
            // GRAPH
            for (var i=0; i<lineConfigArray.length;i++) {
                var graph = new AmCharts.AmGraph();
                graph.type = "line"; 
                graph.title = lineConfigArray[i].title;
                graph.valueField = lineConfigArray[i].valueField;
                graph.lineAlpha = 1;
                graph.lineColor = lineConfigArray[i].lineColor;
                chart.addGraph(graph);
            }
    
            // CURSOR
            var chartCursor = new AmCharts.ChartCursor();
            chartCursor.cursorPosition = "mouse";
            chartCursor.categoryBalloonDateFormat = "MM DD JJ:NN";
            chart.addChartCursor(chartCursor);
    
            // SCROLLBAR
            var chartScrollbar = new AmCharts.ChartScrollbar();
            chart.addChartScrollbar(chartScrollbar);
            
            // LEGEND
            var legend = new AmCharts.AmLegend();
            legend.marginLeft = 110;
            chart.addLegend(legend);
            
            // WRITE
            chart.write(chartDiv);
            console.log('end draw chart: ' + getNow());
        }
    
        function convertDate(chartData, timeStampFieldName, dateConvertFunc) {
            for (var i=0; i<chartData.length;i++) {
                var timeStamp_i = chartData[i][timeStampFieldName == null ? "timeStamp": timeStampFieldName];
                if (typeof dateConvertFunc === 'function') {
                    chartData[i].timeStamp = dateConvertFunc(timeStamp_i);
                }
                else {
                    chartData[i].timeStamp = new Date(timeStamp_i);
                }
            }
            return chartData;
        }
    
        function zoomChart() {
            globalChart.zoomToIndexes(0, globalChartData.length - 1);
        }

     客户端使用方法 :

    AmCharts.ready(function () {
                        
                        var drawLoadperf = function() {
                            $.ajax({
                                    dataType: "json",
                                    url: httpPrefix + '/controllers/sls/obtainNcLoad',
                                    data: 'Category=load_log_index&' + params,
                                    success: function(data) {
                                        var chartData = convertDate(data.result.data, "time");
                                           generateChart('Loadperfchartdiv', chartData, 
                                                     {'title': 'Load'}, 
                                                     [{'title':'load_1', 'valueField': 'ldavg_1', 'lineColor': '#ff0000'},
                                                      {'title':'load_5', 'valueField': 'ldavg_5', 'lineColor': '#00ff00'},
                                                      {'title':'load_15', 'valueField': 'ldavg_15', 'lineColor': '#0000ff'}]);
                                     }
                            });    
                        }
    }

            amcharts 效果图:

            

            

            4.  使用 highcharts 绘制:

            需要导入:   

    <script src="../jquery-1.10.1.min.js" type="text/javascript"></script>
            <script src="../highcharts.js" type="text/javascript"></script>   
            <script src="../drawchart_highcharts.js" type="text/javascript"></script>

          drawchart_highcharts.js 是基于 highcharts 的在同一坐标中绘制多个图形的客户端接口。点击可以放大显示,再点击则还原到原来的视图。

    /**
     * 使用 highcharts 绘制时间趋势曲线图
     * 
     * generateChart:
     *     chartDiv  绘图所需要的 DIV 区域名称;
     *     chartData 绘图所需要的数据
     *     chartConfig 绘图的全局配置对象
     *     lineConfigArray  每个曲线图的配置对象(配置Y轴)
     * 
     */
    Highcharts.setOptions({
        global: {
            useUTC: false
        },
        lang: {
            resetZoom: '还原视图'
        }
        
    });
    function generateChart(chartDiv, chartData, chartConfig, lineConfigArray) {
        var chartObj = {
            chart: {
                zoomType: 'x',
                events: {
                    // 点击图表后在指定区域 zoomUpDiv 放大显示
                    click: null
                }
            },
            // 去掉 highcharts.com 链接
            credits: {
                enabled: false,
                text: ''
            },
            plotOptions: {
                series: {
                    // 去掉点的marker, 使图形更美观
                    marker: {
                        enabled: false,
                        states: {
                            hover: {
                                enabled: true
                            }
                        }
                    }
                }
            },
            series: [],
            xAxis: {
                type: 'datetime',
                dateTimeLabelFormats: {
                    hour: '%m-%d %H:%M'
                }
            },
            yAxis: {
                title: {
                    text: ''
                },
                min: 0
            },
            tooltip: {
                crosshairs: true,
                shared: true,
                formatter: function() {  // 当鼠标悬停图表上时, 格式化提示信息
                    var tipText = '<b>' + Highcharts.dateFormat('%m-%d %H:%M', this.x) + '</b>';
                    $.each(this.points, function(i, point) {
                        tipText += '<br/>'+ point.series.name +': '+ point.y;
                    });
                    return tipText;
                }
            },
            title: {
                // 不显示图表标题
                text: null
            }
        };
        // 在同一坐标中绘制多个曲线图
        for (var i=0; i<lineConfigArray.length;i++) {
            var subseries = {
                name: lineConfigArray[i].title,
                data: extract(chartData, lineConfigArray[i].valueField),
                color: lineConfigArray[i].lineColor
            };
            chartObj.yAxis.title.text = chartConfig.title;
            chartObj.series.push(subseries);
        }
        // 点击图表后在指定区域 zoomUpDiv 放大显示
        chartObj.chart.events.click = function(event) {
            var zoomUpDiv = $('#zoomUpDiv');
            if (zoomUpDiv != null) {
                $('#zoomUpDiv').css('display', 'block');
                $('.chartdiv').css('display', 'none');
                chartObj.chart.events.click = function(event) {
                    $('#zoomUpDiv').css('display', 'none');
                    $('.chartdiv').css('display', 'block');
                };
                $('#zoomUpDiv').highcharts(chartObj);
            }
        };
        $("#"+chartDiv).highcharts(chartObj);
        
    }
    
    /**
     * 指定后台返回的时间字段为 timeStampFieldName , 若不指定则默认为 timeStamp , 
     * 并利用自定义回调函数 dateConvertFunc 统一为时间戳进行处理
     */
    function convertDate(chartData, timeStampFieldName, dateConvertFunc) {
        for (var i=0; i<chartData.length;i++) {
            var timeStamp_i = chartData[i][timeStampFieldName == null ? "timeStamp": timeStampFieldName];
            if (typeof dateConvertFunc === 'function') {
                // 如果给定了自定义的时间转换回调函数, 则使用该函数
                chartData[i].timeStamp = dateConvertFunc(timeStamp_i);
            }
            else if (typeof timeStamp_i === 'number') {
                // 适用于时间戳
                chartData[i].timeStamp = timeStamp_i;
            }
            else {
                // 适用于格式 "Sun Sep 29 17:24:07 2013", "2013-09-29 17:23:09"
                chartData[i].timeStamp = new Date(timeStamp_i);
            }
        }
        return chartData;
    }
    
    /**
     * 从 chartData 中抽取出 valueField 数据
     */
    function extract(chartData, valueField) {
        var valueData = [];
        var i=0, len = chartData.length;
        for (i=0; i<len; i++) {
            valueData.push([chartData[i].timeStamp, parseFloat(chartData[i][valueField])]);
        }
        return valueData;
    }

     客户端使用: 

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
            <title>宿主机性能状态曲线图</title>
            <script src="../jquery-1.10.1.min.js" type="text/javascript"></script>
            <script src="../highcharts.js" type="text/javascript"></script>   
            <script src="../drawchart_highcharts.js" type="text/javascript"></script>
            <link rel="stylesheet" type="text/css" href="../resources/css/chart.css" />
            <script type="text/javascript">
                
                $(document).ready(function () {
                    
                    var iframeurl = parent.document.getElementById("ncperf").src
                    var params = iframeurl.substring(iframeurl.lastIndexOf('?')+1);
                    $(function () {
                        
                        var drawLoadperf = function() {
                            $.ajax({
                                    dataType: "json",
                                    url: httpPrefix + '/controllers/sls/obtainNcLoad',
                                    data: 'Category=load_log_index&' + params,
                                    success: function(data) {
                                        var chartData = convertDate(data.result.data, "time");
                                           generateChart('Loadperfchartdiv', chartData, 
                                                     {'title': 'Load'}, 
                                                     [{'title':'load_1', 'valueField': 'ldavg_1', 'lineColor': '#f58220'},
                                                      {'title':'load_5', 'valueField': 'ldavg_5', 'lineColor': '#00ff00'},
                                                      {'title':'load_15', 'valueField': 'ldavg_15', 'lineColor': '#0000ff'}]);
                                     }
                            });    
                        }
                        
                        var drawCpuperf = function() {
                            $.ajax({
                                     dataType: "json",
                                     url: httpPrefix + '/controllers/sls/obtainNcCpuUsage',
                                     data: 'Category=dom0_log_index&' + params,
                                     success: function(data) {
                                         var chartData = convertDate(data.result.data, "time");
                                            generateChart('CpuUsageperfchartdiv', chartData, 
                                                      {'title': 'Cpu 使用率(%)'}, 
                                                      [{'title':'usr', 'valueField': 'usr', 'lineColor': '#f58220'},
                                                       {'title':'sys', 'valueField': 'sys', 'lineColor': '#00ff00'},
                                                       {'title':'idle', 'valueField': 'idle', 'lineColor': '#0000ff'},
                                                       {'title':'iowait', 'valueField': 'iowait', 'lineColor': '#ffe600'}]);
                                      }
                            });
                        }
                        
                        var drawNetworkperf = function() {
                            $.ajax({
                                      dataType: "json",
                                      url: httpPrefix + '/controllers/sls/obtainNcNetworkflow',
                                      data: 'Category=netflow_log_index&' + params,
                                      success: function(data) {
                                          var chartData = convertDate(data.result.data, "time");
                                         generateChart('Networkflowchartdiv', chartData, 
                                                   {'title': '网络流量 (KB/s)'}, 
                                                   [{'title': 'RECV_BYTES', 'valueField': 'rxkB', 'lineColor': '#f58220'},
                                                    {'title': 'TRAN_BYTES', 'valueField': 'txkB', 'lineColor': '#00ff00'}]);
                                      }
                           });
    
                        }
                        
                        var drawIoperf = function() {
                            $.ajax({
                                      dataType: "json",
                                      url: httpPrefix + '/controllers/sls/obtainNcIoperf',
                                      data: 'Category=iostat_log_index&' + params,
                                      success: function(data) {
                                          var chartData = convertDate(data.result.data, "time");
                                           generateChart('Iorwperfchartdiv', chartData, 
                                                 {'title': 'io读写 (KB/s)'}, 
                                                 [{'title': 'read_iops', 'valueField': 'rkB_s', 'lineColor': '#f58220'},
                                                  {'title': 'write_iops', 'valueField': 'wkB_s', 'lineColor': '#00ff00'}]);
                                           
                                           generateChart('Ioutilchartdiv', chartData, 
                                                {'title': 'io利用率 (%)'}, 
                                                [{'title': 'ioutil', 'valueField': 'util', 'lineColor': '#f58220'}]);
                                        }
                            });
                        }
                        
                        // 间隔 一段时间 后发送下一个异步请求, 避免服务端线程竞争导致错误
                        setTimeout(drawCpuperf, 500);
                        setTimeout(drawNetworkperf, 2000);
                        setTimeout(drawIoperf, 3500);
                        drawLoadperf();
                    });
                    
                }); // $document
                
            </script>
        </head>
        
        <body>
            <div id="zoomUpDiv"></div>
            <div id="perfcharts">
                <div id="Loadperfchartdiv" class="chartdiv"></div>
                <div id="CpuUsageperfchartdiv" class="chartdiv"></div> 
                <div id="Networkflowchartdiv" class="chartdiv"></div> 
                <div id="Iorwperfchartdiv" class="chartdiv"></div> 
                <div id="Ioutilchartdiv" class="chartdiv"></div> 
            </div>
        </body>
    
    </html>

          样式文件: chart.css

    * {font-family: 微软雅黑, 宋体, san-serif!important}
    
    .chartdiv { 
        float: left; 
        margin: 5px 15px 5px 10px; 
        width: 45%; 
        height: 150px; 
    }
    
    #zoomUpDiv { 
        display: none; 
        position: absolute;
        top: 20px;
        left: 10px;
        margin: 10px 15px 10px 10px; 
        width: 95%; 
        height: 80%;
        z-index: 5;
    }

          highcharts  效果图

          

          

  • 相关阅读:
    VIJOS-P1340 拯救ice-cream(广搜+优先级队列)
    uva 11754 Code Feat
    uva11426 GCD Extreme(II)
    uvalive 4119 Always an Interger
    POJ 1442 Black Box 优先队列
    2014上海网络赛 HDU 5053 the Sum of Cube
    uvalive 4795 Paperweight
    uvalive 4589 Asteroids
    uvalive 4973 Ardenia
    DP——数字游戏
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/4037728.html
Copyright © 2011-2022 走看看