使用 highchart 绘制柱状图的通用方法与接口
2014-01-25 17:06
253 查看
本文给出使用 highchart 绘制柱状图的通用方法与接口, 只要指定相应的数据结构和配置, 就可以直接拿来使用。
一、 数据结构与基本接口
一般绘制图形, 会涉及到较复杂的数据结构, 比如使用 jsPlumb 绘制拓扑图的通用接口 。方法是, 首先要弄清楚绘制图形所需要的数据结构,然后根据API文档设计一个公共接口,
并写好详细的文档,避免日后忘记。先从最基本的接口开始, 见下面代码。 这是根据静态示例, 将需要动态生成或配置数据的地方抽取出来做成的接口。
二、 对象数组与结构转化
通常, 从服务端后台返回的数据结构是对象数组, 要使用基本接口来绘制, 就需要进行数据结构转化。 因此, 在基本接口之上, 可以构建一个高层接口, 见如下代码所示。 如果要转化的数据结构比较复杂, 那么, 可以拿一个静态的输入/输出数据示例作为范本来辅佐思考, 先通过硬编码来实现目标, 然后再将硬编码用可配置项替换掉, 达到可扩展、灵活的目标。
三、 使用接口
四、 效果图
![](http://img.my.csdn.net/uploads/201401/25/1390641380_2914.PNG)
五、 小结
要绘制柱状图, 需要对数据结构和算法有较好的掌握, 能够自由地在各种数据结构中进行转换。通过此例, 是想再次说明了结构与算法在实际开发工作中的应用。 当然, 文中给出的代码并非是最优的, 作为一个基本的解法, 里面还是有很多可改进之处。
一、 数据结构与基本接口
一般绘制图形, 会涉及到较复杂的数据结构, 比如使用 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>
四、 效果图
五、 小结
要绘制柱状图, 需要对数据结构和算法有较好的掌握, 能够自由地在各种数据结构中进行转换。通过此例, 是想再次说明了结构与算法在实际开发工作中的应用。 当然, 文中给出的代码并非是最优的, 作为一个基本的解法, 里面还是有很多可改进之处。
相关文章推荐
- 使用 highchart 绘制柱状图的通用方法与接口
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 常量,字段,构造方法 调试 ms 源代码 一个C#二维码图片识别的Demo 近期ASP.NET问题汇总及对应的解决办法 c# chart控件柱状图,改变柱子宽度 使用C#创建Windows服务 C#服务端判断客户端socket是否已断开的方法 线程 线程池 Task .NET 单元测试的利剑——模拟框架Moq
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- Java学习之容器上(Collection接口常用方法,Iterator接口,使用foreach循环遍历Collection集合元素,Set集合通用知识(Hashset类,hashcode()与Lin
- 使用 JsPlumb 绘制拓扑图的通用方法
- 【转】使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 使用pandas中的DataFrame数据绘制柱状图的方法
- 使用 JsPlumb 绘制拓扑图的通用方法
- highchart插件使用 生成 柱状图
- 使用 JsPlumb 绘制拓扑图的通用方法
- 本人在代码中经常使用到两种控件 highchart 和highstock。现在分享一下两种控件互换方法
- 使用 amcharts 和 highcharts 绘制多曲线时间趋势图的通用方法
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 使用DevExpress的WebChartControl控件绘制图表(柱状图、折线图、饼图)
- 使用 amcharts 和 highcharts 绘制多曲线时间趋势图的通用方法
- 使用JsPlumb绘制拓扑图的通用方法
- Java学习之容器上(Collection接口常用方法,Iterator接口,使用foreach循环遍历Collection集合元素,Set集合通用知识(Hashset类,hashcode()与LinkedHashSet类))