• 使用 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  效果图

          

          

  • 相关阅读:
    JSP 静态文件路径配置
    java 类拷贝
    spring security demo
    NYOJ-1057-寻找最大数(三)
    nyoj-1036-非洲小孩
    POJ-3617-Best Cow Line
    NYOJ-891-找点
    大平神出的一道双向链表题
    ZOJ-1360 || POJ-1328——Radar Installation
    POJ-2386-Lake Counting
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/4037728.html
Copyright © 2020-2023  润新知