去年,苏嗲有提过HightChart控件.详见highcharts.com,自己一直有关注.最新出的版本是1.2.4,基本稳定下来了.这个网站的人员宣称,在1.5版本时实现3D效果.超期待哦.还等什么,拿过来给我们的前台框架添下光啊.
拿来主义是不错,可是在于嗲的前台上扩展有些困难哦.所幸,经过好几天不懈的努力.总算实现了.
第一个麻烦是基于Ext适配器的实现,因为HightChart组件是基于Jquery或者MooTools框架的,总不能为了一个报表组件引进Jquery或MoolTools吧.以下是部分代码:
window.HighchartsAdapter = { getAjax: function (url, callback){ Ext.Ajax.request({ url: url, success: function (response){ callback(response.responseText); } }); }, hyphenate: function (str){ return str.replace(/([A-Z])/g, function (a, b){ return '-' + b.toLowerCase(); }); }, addEvent: function (el, event, fn){ var xel = Ext.get(el); if (xel) xel.addListener(event, fn); }, fireEvent: function (el, event, eventArguments, defaultFunction){// if fireEvent is not available on the object, there hasn't been added if (el.fireEvent) el.fireEvent(event, eventArguments);// fire the default if it is passed and it is not prevented above if (defaultFunction) defaultFunction(event); }, animate: function (el, params, options){//jQuery(el).animate(params, options); var element = Ext.fly(el); var opt = {}; var duration = 1.5; var callback = null; for (var p in params){ opt[p] = { to: (params[p] + "").replace("px", "") }; } for (var l in options){ if (l === "complete") callback = options[l]; } element.animate(opt, duration, callback, "easeOut", "run"); }, each: function (arr, fn){ for (var i = 0, len = arr.length; i < len; i++) if (fn.call(arr[i], arr[i], i, arr) === false) return i; }, map: function (arr, fn){ var results = []; if (arr) for (var i = 0, len = arr.length; i < len; i++){ results[i] = fn.call(arr[i], arr[i], i, arr); } return results; }, merge: function (){ var args = arguments; return Sail.jqextend(true, null, args[0], args[1], args[2], args[3]); }, grep: function (arr, fn){ return arr.filter(fn); } }; var merge = window.HighchartsAdapter["merge"];
在于嗲平台上扩展的实现:
Sail.widget.ext.ux_chart = function (config){ this.title = "myReport"; this.sub_title; this.url; this.theme = "grid"; this.stacking = ''; this.x_rotation = 0; this.y_rotation = 0; this.series_root = "dataset.report"; this.xAxis_root = "dataset.categories"; this.margin = Highcharts["defaultOptions"]["chart"]["margin"]; this.legend_layout = ''; this.xAxis = []; this.yAxis = [];//[{name:"",color:"",unit:""}] this.series = [];//[{name:"",type:"",data:[]}] this.formatter = function (){ if (this.point && this.point.name && Sail.isEmpty(this.point.name)) return '<b>' + this.point.name + '</b><br/>' + this.y; else return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y; }; Sail.widget.ext.ux_chart.superclass.constructor.call(this, config); }; Ext.extend(Sail.widget.ext.ux_chart, Sail.widget, { defaultHeight: 400, defaultWidth: 800, defaultSeriesType: "line", initComponent: function (){}, clean_config: function (){ this.title = "myReport"; this.sub_title; this.url = ""; this.theme = "grid"; this.stacking = ''; this.legend_layout = ''; this.x_rotation = 0; this.y_rotation = 0; this.margin = Highcharts["defaultOptions"]["chart"]["margin"]; this.series_root = "dataset.report"; this.xAxis_root = "dataset.categories"; this.xAxis = []; this.yAxis = [];//[{name:"",color:"",unit:""}] this.series = [];//[{name:"",type:"",data:[]}] this.formatter = function (){ if (this.point && this.point.name && ! Sail.isEmpty(this.point.name)) return '<b>' + this.point.name + '</b><br/>' + this.y; else return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y; } }, getHeight: function (){ return this.height || this.defaultHeight; }, setHeight: function (height){ this.getOCD().style.height = height || this.getHeight(); }, getWidth: function (){ return this.width || this.defaultWidth; }, setWidth: function (width){ this.getOCD().style.width = width || this.getWidth(); }, getEl: function (){ return this.el; }, setTheme: function (theme){ this.theme = theme; Highcharts.setOptions(_THEMES[this.theme]); }, getTheme: function (){ return this.theme; }, init_config: function (config){ if ( ! Sail.isEmpty(config)) Ext.apply(this, config); this.options = {}; Highcharts.setOptions(_THEMES[this.theme]); this.options = { chart: { renderTo: this.getOCD(), margin: this.margin, defaultSeriesType: this.defaultSeriesType }, credits: { enabled: true, href: "http://www.talkweb.com.cn", target: "_self", text: "talkweb.com.cn" }, title: { text: this.title }, subtitle: { text: this.sub_title }, xAxis: [{ categories: this.xAxis, labels: { rotation: this.x_rotation || 0, align: 'center', style: { font: 'normal 13px Verdana, sans-serif' } } }], yAxis: ! Sail.isEmpty(this.yAxis) ? this.yAxis : { title: { enabled: false, text: "" } }, tooltip: { enabled: true, formatter: this.formatter }, legend: { layout: 'vertical', style: { left: '120px', bottom: 'auto', right: 'auto', top: '100px' }, backgroundColor: '#FFFFFF' }, plotOptions: { column: { dataLabels: { rotation: this.y_rotation || 0, enabled: this.y_rotation !== 0, color: '#FFFFFF', align: "right" }, stacking: Sail.isEmpty(this.stacking) ? '' : "normal" }, area: { stacking: 'percent', lineColor: '#ffffff', lineWidth: 1, marker: { lineWidth: 1, lineColor: '#ffffff' } } }, series: this.series }; if (Sail.isEmpty(this.legend_layout)) this.options.legend = Highcharts["defaultOptions"]["legend"]; if (Sail.isArray(this.yAxis) && ! Sail.isEmpty(this.yAxis)){ var units_rs = {}; this.options.yAxis = []; Ext.each(this.yAxis, function (el, i, s){ this.options.yAxis.push({ title: { text: el.name, margin: i > 0 ? 70 * i : 70, style: { color: el.color } }, labels: { formatter: function (){ return this.value + el.unit || ""; }, style: { color: el.color } }, opposite: i > 0 ? true : false }); units_rs[el.name] = el.unit || ""; }, this); this.options.tooltip["formatter"] = function (){ return '<b>' + this.series.name + '</b><br/>' + this.x + ': ' + this.y + units_rs[this.series.name]; }; } if (this.url){ var self = this; Sail.postData(this.url, {}, function (flag, rs){ if (flag){ self.xAxis = Sail.splat(Sail.getSubObj(rs, self.xAxis_root)); self.series = Sail.splat(Sail.getSubObj(rs, self.series_root)); self.options.xAxis[0]["categories"] = self.xAxis; self.options.series = self.series; self.el = new Highcharts.Chart(self.options); } }); } else this.el = new Highcharts.Chart(this.options); }, load: function (config){ if (this.el) this.el.destroy(); var this_obj = this; (function (){ this_obj.clean_config(); }).createSequence(function (){ this.init_config(config); }, this)(); }, createWidgetElement: function (){ this.init_config(); } });
以下是使用示例:
改变数据源
示例如图:
配置参数说明,hightchart组件的配置参数非常麻烦.在于嗲平台上扩展后,虽然简化了配置.但要配合一定的后台数据结构.这个还可以再修正.
以下作又部分参数作一个简短的说明.
type : "ux_chart" 报表的组合类型,值固定.
name : 报表名称,方便之后引用.
title :报表标题.
sub_title :报表副标题.
url:请求数据地址.
theme:报表皮肤.有dark-blue,dark-green,grid,default,gray,minimal.默认为grid,个人觉得这个最好看.
series_root:Y轴后台数据结构名称定制.默认为"dataset.report".
xAxis_root:X轴后台数据结构名称定制.默认为"dataset.categories".
yAxis:Y轴坐标轴定制,可以定义多个,详见示例.
legend_layout:定义图例的布局.horizontal or vertical.
x_rotation:x轴旋转角度,默认值0
y_rotation:y轴旋转角度,默认值0
margin:报表边辐.有默认值
svn地址 http://svn.talkweb.com.cn/svn/TBpl/MES产品化项目/01_工作区/04_编码/GUIF
示例文件名称 : ux_chart_1.html ,注意文件的引用.如图:
总结一下:
发布了一个ms_util.js文件,视需要可以作为对框架文件的必要补充.框架的文件未变动,所以对所有项目是兼容的.
这个文件主要是提供了hightchart报表控件的扩展,引进了hightchart库.
提供了一个遍历表单组件的方法.非常灵活哦.
简化了combox组件的配置,提供一个简单的赋值方法.
为sDate组件提供了set_current_date方法以设置默认值.
修正了框架一些不太好的地方.
重点说明一下:框架已经提供了报表的实现,虽然简单.但满足了作为报表的所有功能.并且在许多项目中有应用.这个是于嗲的原创,想学习js实现报表的话,不妨将这部分好好研究一下.另外,于嗲的框架平台的扩展性还是很强的,再赞一个.