在Rails中用Fusioncharts开发图表
? ? ? ??开发一个报表可供选择的报表很多,如openflashchart,hightchart,fusioncharts等。都是一些不错的选择。对比之下,frusioncharts将图表生成图片返回给前端或者保存在后端更容易,而且fusioncharts的渲染是将数据和flash分离,提供多数据组合展示。所以,我在开发处理图表时选择了fusioncharts(以下简称FC)。
? ? ?FC还有个免费版本,叫:FusionChartsFree。但是只有22个图表模板。而标准版本的FC有近50个图表模板。
? ? ?FC的实现原理是基于flash,解析json/xml数据,然后再生成相应的图表。查看官方文档可以发现有不少的模板可供使用,并且我发现老外写的文档就是好,不仅将每个图表的属性、示例给出来,还提供了一些现成的工程供我们使用。很多诸如生成图表的方法、导出图片什么的js也写好了。直接copy过来用就可以了。
? ? ? ? 说了这么多废话,现在进入正题了。下面就是开发一个FC图表的完整过程记录:
def render_chart(chart_swf, str_url, str_xml, chart_id, chart_width, chart_height, debug_mode, register_with_js, &block) chart_width=chart_width.to_s chart_height=chart_height.to_s debug_mode_num="0"; register_with_js_num="0"; if debug_mode==true debug_mode_num="1" end if register_with_js==true register_with_js_num="1" end html = <<END_OF_STRING#{content_tag("div", "\n\t\t\t\tChart.\n\t\t", {:id=>chart_id+"Div", :align=>"center"})} <script type="text/javascript"> var chart_#{chart_id}=new FusionCharts("#{chart_swf}","#{chart_id}",#{chart_width},#{chart_height},#{debug_mode_num},#{register_with_js_num}); var xml_data = '#{str_xml}'; chart_#{chart_id}.setDataXML(unescape(xml_data)); chart_#{chart_id}.render("#{chart_id}Div"); </script>END_OF_STRING html.html_safe end?
? ?5. 在视图页面中写上<%= render_chart "/FusionCharts/StackedBar2D.swf", "", str_xml, "chart_name", 600, 450, false, false %>即可展示出图表来了。这里选择了Bar2D这个图表。
? ? ? ?等一下,我们似乎忘了什么东西?对,就是这个xml数据怎么来的。这个本来是很简单的问题,看下官方文档和demo就知道了。但是如何生成xml及一些中文乱码问题会比较纠心。
? ? ? 首先,如何生成xml。在Rails中生成xml还是很容易的,插件也很多,我使用的Nokogiri插件来生成xml。利用Builder类可以方便地生成想要的xml。其实有个gem包就叫fusioncharts,里面也封装了一些基本的类和to_xml方法。用了感觉还不如自己用Builder构造xml方便。
? ? ? 其次,如果我们不做处理就直接将builder.to_xml作为xml数据的话,我们会发现中文在图表中显示异常。页面编码为utf-8。数据库、源码也是默认的utf-8,但是偏偏Nokogiri的to_xml后中文就面目全非了。但是查看页面源代码时发现中文变成了乱码。解决办法其实在官方提供的lib中已经提供了:lib/xml_helper.rb下的escape_builder_xml方法。其实我的做法是没使用这个方法,是用一句话就可将字符编码escape,然后再调用js的unescape方法就可正确显示了:builder.doc.children.to_xml.gsub(/[\n;]/, "").gsub(/&#x/, "%u")。如果调用rails自带的to_xml。中文会被转成uicode,更是奇怪,处理方式又不一样。
? ? ? 最后我们就发现在中文正常显示了。如上图所示。
? ? ? FC支持右键保存成图片返回给客户端或者提交图片数据到后端,由后端生成图片保存在服务器。如果想要服务器自动以图片的方式保存FC图表,比如可能要在邮件中发送这样的需求。那就需要用到FCr的导出功能。还是查找刚才下载FC压缩包中的文件夹:ExportHandlers/RoR。这里面有个工程示例(rails version=2.3.8)。这里面的代码可以直接copy出来用。用例服务器端生成图片用。前端代码可以查看官方示例页面。核心代码如下:
function exportCharts(exportFormat) { initiateExport = true; for (var chartRef in FusionCharts.items) { if (FusionCharts.items[chartRef].exportChart) { FusionCharts.items[chartRef].exportChart({ "exportFormat" : exportFormat}); //成功事件 } else { //alert("生成图片失败了!"); //失败事件 } } }?
? ? ? ? 这里要注意的是:xml中一定要指定提交到后端的URL。示例:
<graph yAxisName="BUG" exportHandler="http://hostname/fusioncharts/fc_exporter/index" decimalPrecision="0" exportAtClient="0" showValues="1" exportAction="save" baseFontSize="12" caption="%u6D3B%u52A8BUG%u8D70%u52BF%u56FE" xAxisName="%u65F6%u95F4" exportEnabled="1"> <set value="237" name="2011-05-19"/> <set value="240" name="2011-05-20"/> <set value="240" name="2011-05-21"/> <set value="240" name="2011-05-22"/> <set value="240" name="2011-05-23"/> <set value="240" name="2011-05-24"/> <set value="242" name="2011-05-25"/> <set value="242" name="2011-05-26"/> <set value="242" name="2011-05-27"/> <set value="242" name="2011-05-28"/> <set value="242" name="2011-05-29"/> <set value="242" name="2011-05-30"/> <set value="242" name="2011-05-31"/> <set value="242" name="2011-06-01"/> <set value="242" name="2011-06-02"/> <set value="242" name="2011-06-03"/> <set value="242" name="2011-06-04"/> <set value="242" name="2011-06-05"/> <set value="242" name="2011-06-06"/> <set value="242" name="2011-06-07"/> <set value="243" name="2011-06-08"/> <set value="244" name="2011-06-09"/> <set value="244" name="2011-06-10"/> <set value="244" name="2011-06-11"/> <set value="244" name="2011-06-12"/> <set value="244" name="2011-06-13"/> <set value="245" name="2011-06-14"/> <set value="246" name="2011-06-15"/> <set value="246" name="2011-06-16"/> <set value="246" name="2011-06-17"/> <set value="246" name="2011-06-18"/></graph>?
? ? 如果服务器的静态资源是单独部署的,那么最后将这个生成图片的rails应用部署在那个静态文件服务器上,这样免得又去同步静态文件资源到静态文件服务器。
?