使用 highchart 繪製柱狀圖的通用方法與介面

來源:互聯網
上載者:User


       本文給出使用 highchart 繪製柱狀圖的通用方法與介面, 只要指定相應的資料結構和配置, 就可以直接拿來使用。


       一、  資料結構與基本介面  

       一般繪製圖形, 會涉及到較複雜的資料結構, 比如使用 jsPlumb 繪製拓撲圖的通用介面 。方法是, 首先要弄清楚繪製圖形所需要的資料結構,然後根據API文檔設計一個公用介面, 並寫好詳細的文檔,避免日後忘記。先從最基本的介面開始, 見下面代碼。 這是根據靜態樣本, 將需要動態產生或配置資料的地方抽取出來做成的介面。      

/** * 建立柱狀圖(基本介面) * @param chartDivName  用來繪製柱狀圖的 DIV-ID 值 * @param chartData     柱狀圖資料結構 *                      categories: ['c1', 'c2', ..., 'Cn'] *                      series: [ *                          { name: 'var1', data: [d11, d12, ..., d1n]},   *                          { name: 'var2', data: [d21, d22, ..., d2n]}, *                          ..., *                          { name: 'varN', data: [dn1, dn2, ..., dnn]} *                      ] * @param chartConfig  柱狀圖全域配置 *                        title:  圖表標題 * @returns */function generateColumnChart(chartDivName, chartData, chartConfig) {var displayFormatter = function() {  // 當滑鼠移至上方圖表上時, 格式化提示資訊    var tipText = '<b>' + this.x + '</b>';    var total = 0;    $.each(this.points, function(i, point) {        total += point.y;        });        $.each(this.points, function(i, point) {        tipText += '<br/>'+ point.series.name +': '+ Highcharts.numberFormat((point.y*100 / total), 2) + '%' + '(' + point.y + ')';        });        return tipText;    };        var chartObj = obtainCommonChartObj(displayFormatter);chartObj.title.text = chartConfig.title;chartObj.xAxis.categories = chartData.categories;chartObj.series = chartData.series;var seriesNum = (chartData.series == null ? 0 : chartData.series.length);for (var k=0; k < seriesNum; k++) {chartObj.series[k].type = 'column';}var chartdiv = $('#'+chartDivName);chartdiv.highcharts(chartObj);}function obtainCommonChartObj(displayFormatterFunc) {   var commonChartObj = {chart: {zoomType: 'x',events: {click: null},resetZoomButton: {position: {                    x: -10,                    y: 10                },                relativeTo: 'chart'}},// 去掉 highcharts.com 連結credits: {enabled: false,text: ''},plotOptions: {series: {// 去掉點的marker, 使圖形更美觀                marker: {                    enabled: false,                    states: {                        hover: {                            enabled: true                        }                    }                },                turboThreshold: 0,                events: {                click: null                }            },            line: {            lineWidth: 1.5            }},series: [],xAxis: {},yAxis: {title: {text: ''},    min: 0},tooltip: {crosshairs: true,shared: true,            formatter: displayFormatterFunc        },            title: {    // 動態顯示圖表標題    text: '',    align: 'center',    style: {    fontSize: '12px',                margin: '3px'    }    }};   return commonChartObj ;}
    

       二、 對象數組與結構轉化

       通常, 從服務端後台返回的資料結構是對象數組, 要使用基本介面來繪製, 就需要進行資料結構轉化。 因此, 在基本介面之上, 可以構建一個高層介面, 見如下代碼所示。 如果要轉化的資料結構比較複雜, 那麼, 可以拿一個靜態輸入/輸出資料樣本作為範本來輔佐思考, 先通過寫入程式碼來實現目標, 然後再將寫入程式碼用可配置項替換掉, 達到可擴充、靈活的目標。   

/** * 建立柱狀圖(針對對象數組的高層介面) * @param chartDivName  用來繪製柱狀圖的 DIV-ID 值 * @param chartData     對象數組 *                      categories: ['c1', 'c2', ..., 'Cn'] *                      data: *                      [{'field1': 'v11', 'field2': 'v12', ..., 'fieldN': 'v1N'}, *                       {'field1': 'v21', 'field2': 'v22', ..., 'fieldN': 'v2N'}, *                       ...,  *                       {'field1': 'vN1', 'field2': 'vN2', ..., 'fieldN': 'vNN'}] * @param chartConfig   柱狀圖全域配置 *                       title: 圖表標題 *                       categoryField: 類別欄位 *                       groupField: 用於建立 legend 的分組欄位 *                       valueField: 用於顯示 Y 軸的欄位 * @returns */function generateColumnChartHighLevel(chartDivName, chartData, chartConfig) {    var groupField = chartConfig.groupField;var valueField = chartConfig.valueField;var categoryField = chartConfig.categoryField;var categories = chartData.categories;    var groupedChartData = groupByField(chartData.data, groupField);        var series = [];    for (var i=0; i< groupedChartData.length; i++) {var groupName = groupedChartData[i][groupField];var groupData = groupedChartData[i]['data'];var fieldData = [];for (var k=0; k < groupData.length; k++) {// 每個分類的值必須與相應的分類對應, 應對這樣的情況// 對於每個 groupField, 並不是所有 categories 都有值, 可以通過測試例子看出來// 蘋果在 Q3 對應的值是缺失的, 香蕉在 Q2 對應的值是缺失的 var categoryPosition =  getCategoryPosition(categories, groupData[k][categoryField]);if (categoryPosition != -1) {fieldData[categoryPosition] = groupData[k][valueField];}}for (var j=0; j < categories.length; j++) {// 缺失值填充if (fieldData[j] == null) {fieldData[j] = 0;}}var subseries = {    name: groupName,    data: fieldData,    };series.push(subseries);}var data = {};    data.categories = categories;    data.series = series;generateColumnChart(chartDivName, data, chartConfig);}/** * 檢測 value 在 categories 中的位置 * @param categories * @param value */function getCategoryPosition(categories, value) {for (var index=0; index < categories.length; index++) {if (categories[index] == value) {return index;}}return -1;}/** * 將指定 chartData 資料按照指定欄位的值分類 * eg. [{'timestamp': 'time0', cpu: '0', sys: '15', usr: '20'}, {'timestamp': 'time0', cpu: '1', sys: '16', usr: '21'}, *      {'timestamp': 'time1', cpu: '0', sys: '20', usr: '13'}, {'timestamp': 'time1', cpu: '1', sys: '18', usr: '10'}] * 轉換為 [{ cpu:'0', data: [{'timestamp': 'time0', cpu: '0', sys: '15', usr: '20'}, {'timestamp': 'time1', cpu: '0', sys: '20', usr: '13'}] } , *       { cpu:'1', data: [{'timestamp': 'time0', cpu: '1', sys: '16', usr: '21'}, {'timestamp': 'time1', cpu: '1', sys: '18', usr: '10'}] }]  */var groupByField = function(chartDataGathered, fieldName) {var fieldDataMappingArray = [];var fieldData = {};var i=0, num = (chartDataGathered == null ? 0 : chartDataGathered.length);for (i=0; i<num; i++) {var fieldValue = chartDataGathered[i][fieldName];fieldData = obtainFieldData(fieldDataMappingArray, fieldName, fieldValue);if (fieldData == null) {fieldData = {};fieldData[fieldName] = fieldValue;fieldData['data'] = [];fieldDataMappingArray.push(fieldData);}fieldData['data'].push(chartDataGathered[i]);}return fieldDataMappingArray;}/** * 在 fieldDataMappingArray 中檢測是否有 fieldName = fieldValue 的對象, 若有則返回; 若沒有則返回 null * @param fieldDataMappingArray [{'fieldName': 'fieldValue1', 'data':[]}, {'fieldName': 'fieldValue2', data: []}] * @param fieldName the name of field * @param fieldValue the value of field */var obtainFieldData = function(fieldDataMappingArray, fieldName, fieldValue) {var k=0, dataArrayLength = (fieldDataMappingArray == null ? 0 : fieldDataMappingArray.length);var fieldData = {};var existFieldData = {};if (dataArrayLength == 0) {return null;}for (k=0; k<dataArrayLength; k++) {existFieldData = fieldDataMappingArray[k];if (existFieldData[fieldName] == fieldValue) {return existFieldData;}}return null;}

        三、 使用介面     

<!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>highcharts 繪圖樣本</title>        <script src="jquery-1.10.1.min.js"></script>        <script src="highcharts.js"></script><script src="draw_highcharts.js"></script>        <script type="text/javascript">    $(document).ready(function() { /**   * 一個用於測試基本介面的樣本   * @param chartDivId   */function testGenerateColumnChart(chartDivId) {var categories = ['2013-11', '2013-12', '2014-01'];var series = [ { name: '蘋果', data: [1500, 1300, 1200] }, { name: '桔子', data: [3500, 5000, 2500] }, { name: '香蕉', data: [2000, 1800, 1600] }];var data = {categories: categories, series: series};var chartConfig = { title: '第四季度水果銷量' };generateColumnChart(chartDivId, data, chartConfig);     }     testGenerateColumnChart('testBasicColumnchartdiv');/** * 測試繪製柱狀圖高層介面的測試例子 * @param chartDivId */function testGenerateColChartHighLevel(chartDivId) {var data = [{ time: 'Q1' , fruit: '蘋果', sale: 1500 },             { time: 'Q1' , fruit: '桔子', sale: 1300 },{ time: 'Q1' , fruit: '香蕉', sale: 1400 },{ time: 'Q2' , fruit: '蘋果', sale: 1500 }, { time: 'Q2' , fruit: '桔子', sale: 1900 },{ time: 'Q3' , fruit: '桔子', sale: 1700 },{ time: 'Q3' , fruit: '香蕉', sale: 1800 }];var categories = ['Q1', 'Q2', 'Q3'];var chartData = {categories: categories,data: data};var chartConfig = {title: '季度水果銷量',categoryField: 'time',groupField: 'fruit',valueField: 'sale'}generateColumnChartHighLevel(chartDivId, chartData, chartConfig);                }                testGenerateColChartHighLevel('testAdvancedColumnchartdiv');                });</script><style>body {    font-family: '微軟雅黑', '宋體', 'san-serif';}.chartdiv {    width: 90%;                height: 250px;}</style></head><body><div id="testBasicColumnchartdiv" class="chartdiv"></div>        <div id="testAdvancedColumnchartdiv" class="chartdiv"></div></body></html>
        

        四、

         

        五、 小結

        要繪製柱狀圖, 需要對資料結構和演算法有較好的掌握, 能夠自由地在各種資料結構中進行轉換。通過此例, 是想再次說明了結構與演算法在實際開發工作中的應用。 當然, 文中給出的代碼並非是最優的, 作為一個基本的解法, 裡面還是有很多可改進之處。 

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.