blog迁移至:
http://www.micmiu.com
很久前写过一篇
Open Flash Chart2初步应用,刚接触的可以看看这篇文章。
最近为了实现动态曲线图展示的功能,对Open Flash Chart2又小小研究了下,研究和整合过程中遇到的各种各样的问题,现在对重点问题的解决方法在此总结下,方便自己日后回顾,也希望能给有同样需求的同仁们提供帮助。
本文的重点就是解决OFC2和第三方JS的冲突,基本目录结构:
[一]、Open Flash Chart2中javascript基本方法的介绍
[二]、OFC2与Prototype.js的冲突解决
[三]、OFC2与Ext.Viewport的冲突解决
[四]、动态流量曲线图的demo
ps:
1.本文demo是在tomcat下发布后测试的,涉及的到部分html页面是不能脱离Web应用服务器的
2.demo中的有关js、swf的路径请根据自己项目的路径具体情况调整
【一】OFC2的javascript基本方法
open_flash_chart_data() 将画图的数据以string的方式传递给chart
ofc_ready() 数据加载好后会执行这个函数的
具体的作用及执行顺序可以试着运行下面这个demo页面:ofc2ChartDemoJs.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Open Flash Chart 2 demo</title>
<script type="text/javascript" src="../json2.js"></script>
<script type="text/javascript" src="../swfobject.js"></script>
</head>
<body>
<p>Hello World ofc2</p>
<div id="my_ofc2_chart"></div>
</body>
<script type="text/javascript">
var ofc2_chart_id="my_ofc2_chart";
/*
swfobject.embedSWF("../open-flash-chart.swf", ofc2_chart_id,
"400", "300", "9.0.0", "expressInstall.swf",
{"get-data":"getDemoInitData"},
{"wmode":"transparent"}
);
*/
//如果定义了function:open_flash_chart_data(),则不需要:"get-data":"getDemoInitData";
swfobject.embedSWF("../open-flash-chart.swf", ofc2_chart_id,
"400", "300", "9.0.0", "expressInstall.swf",
{"wmode":"transparent"}
);
function ofc_ready()
{
alert('ofc_ready');
}
function open_flash_chart_data()
{
alert( 'reading data' );
return JSON.stringify(data_1);
}
function findSWF(movieName) {
if (navigator.appName.indexOf("Microsoft")!= -1) {
return window[movieName];
} else {
return document[movieName];
}
}
var data_1 = {
"elements": [
{
"type": "bar",
"values": [9,8,7,6,5,4,3,2,1
]
}
],
"title": {
"text": "demo 1"
}
};
function getDemoInitData(){
return JSON.stringify(data_1);
}
</script>
</html>
运行结果示例图:
OFC2提供
function load()方法,可以更新chart的数据,接下来的动态曲线图,也是基于这个方法来实现的,我们先看一个简单的ofc2ChartDemoLoad.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Open Flash Chart 2 demo</title>
<script type="text/javascript" src="../json2.js"></script>
<script type="text/javascript" src="../swfobject.js"></script>
</head>
<body>
<p>Hello World ofc2</p>
<div id="my_ofc2_chart"></div>
<br>
<a href="javascript:load_data1('my_ofc2_chart')">display data 1</a>
||
<a href="javascript:load_data2('my_ofc2_chart')">display data 2</a>
</body>
<script type="text/javascript">
var ofc2_chart_id="my_ofc2_chart";
swfobject.embedSWF("../open-flash-chart.swf", ofc2_chart_id,
"400", "300", "9.0.0", "expressInstall.swf",
{"get-data":"getDemoInitData"},
{"wmode":"transparent"}
);
function findSWF(movieName) {
if (navigator.appName.indexOf("Microsoft")!= -1) {
return window[movieName];
} else {
return document[movieName];
}
}
var data_0 = {
"elements": [
{
"type": "bar",
"values": [1,2,3,4,5,6,7,8,9]
}
],
"title": {
"text": "demo"
}
};
var data_1 = {
"elements": [
{
"type": "bar",
"values": [9,8,7,6,5,4,3,2,1]
}
],
"title": {
"text": "demo data 1"
}
};
var data_2={
"title":{
"text":"每周水果产量"
},
"elements":[
{
"type":"bar_glass",
"values":[16,8,18,12,16,24,6]
}
],
"x_axis":{
"labels":{
"labels":["星期1","星期2","星期3","星期4","星期5","星期6","星期日"]
}
},
"y_axis":{
"max":30
}
};
function getDemoInitData(){
return JSON.stringify(data_0);
}
function load_data1(movieName) {
var tmp = findSWF(movieName);
tmp.load(JSON.stringify(data_1));
}
function load_data2(movieName) {
var tmp = findSWF(movieName);
tmp.load(JSON.stringify(data_2));
}
</script></html>
运行结果示例图:
【二】、OFC2与prototype.js冲突问题
在我实验的过程中发现,如果只是第一次加载flash,运用函数swfobject.embedSWF(),设置参数"data-file"加载后台json数据时,flash能正常画出曲线图和prototype、jquery没有冲突,IE、FF都能正常显示。但是如果需要调用上面介绍的 load(JSON.stringify(data))这个方法重新画图时会失败,具体现象:在IE下chart不会更新数据,在FF下chart会消失。最后发现JSON.stringify(data) 和prototype.js中的JSON转化为string的方法冲突引起的(prototype1.6.0.3和1.6.1都有冲突),最开始是怀疑json2.js和prototype.js的JSON.stringify(data)转化后的格式不一致引起的,在接下来的测试和调试中发现转化后的格式的确不一致,但这个发现不是问题的根源,最后找了一个折中的方法解决了这个问题:
- 先把json2.js这个文件从页面中里移除
- 然后load(JSON.stringify(chartdata))改成load(Object.toJSON(chartdata))
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Open Flash Chart 2 demo</title>
<script type="text/javascript" src="../../scripts/prototype-1.6.0.2.js"></script>
<script type="text/javascript" src="../swfobject.js"></script>
</head>
<body>
<p>Hello World ofc2</p>
<div id="my_ofc2_chart"></div>
<br>
<input type="button" name="btn" value="stop" onclick="changeRefresh(this)">
</body>
<script type="text/javascript">
var portType = "random";
var portId = "1000";
var portIndex = "5";
var ofc2_chart_id="my_ofc2_chart";
var ofc2_url = 'DrawOfc2RealTimeAction.do';
var flash_param="ofc2_param="+ofc2_chart_id+","+portType+","+portId+","+portIndex;
swfobject.embedSWF("../open-flash-chart.swf", ofc2_chart_id,
"600", "300", "9.0.0", "expressInstall.swf",
{"data-file":ofc2_url+"?"+flash_param},
{"wmode":"transparent"}
);
//refresh_ofc2_chart();
var o_time = setInterval('refresh_ofc2_chart()', 10*1000);
function changeRefresh(obj){
if(obj.value=="stop"){
if(null!=o_time){clearInterval(o_time );}
obj.value="start"
}else{
clearInterval(o_time );
o_time = setInterval('refresh_ofc2_chart()', 10*1000);
obj.value="stop"
}
}
function refresh_ofc2_chart(){
//var pars = Object.toQueryString(par);
var myAjax = new Ajax.Request(ofc2_url,
{
encoding :'UTF-8',
method :'get',
parameters :flash_param,
asynchronous :false,
onComplete : showResponse
}
);
}
function showResponse(rep) {
var chartdata = rep.responseText.evalJSON(true);
//alert(JSON.stringify(chartdata));
var tmp = findSWF(ofc2_chart_id);
x = tmp.load(Object.toJSON(chartdata));
}
function findSWF(movieName) {
if (navigator.appName.indexOf("Microsoft")!= -1) {
return window[movieName];
} else {
return document[movieName];
}
}
</script></html>
【三】OFC2与Ext.Viewport的冲突问题
如果你的页面里用到了Ext.Viewport来布局,会发现在IE下findSWF('ofc2_id').load(Object.toJSON(chartdata));再一次的发生了杯具,FF下一切正常,而在IE下页面会有js错误提示:“未指明的错误”,这个错误的原因至今没有找到,js debug以及后来查了很多资料也没有确切结果,最后在ext的论坛上找了一个有关该问题的讨论,提供了一个扩展js库uxmedia,可以解决该问题,
相关讨论的帖子:
http://www.sencha.com/forum/showthread.php?23983-ux.Media-.Flash-Flex-Components-2.1.2
uxmedia的官网:
http://code.google.com/p/uxmedia/
uxmedia API doc:
http://uxdocs.theactivegroup.com/
基本的解决方法:
- 导入uxmedia的相关js文件要注意文件的先后顺序
- 用Ext.ux.Chart.OFC.Component创建flash chart
- 修改更新数据的相关方法:把findSWF(ofc2_chart_id).load(JSON.stringify(chartdata))改成:
Ext.getDom(ofc2_chart_id).load(Object.toJSON(chartdata));//prototype.js
Ext.getDom(ofc2_chart_id).load(JSON.stringify(chartdata));//json2.js
页面代码片段:
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ include file="/common/taglibs.jsp"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Open Flash Chart 2 demo</title>
<!-- 其他有关Extjs的相关文件自己导入,这里省略-->
<script type="text/javascript" src="ofc2/swfobject.js"></script>
<!-- 注意下面uxmedia的相关文件的顺序-->
<script type="text/javascript"
src="scripts/ext/ux.media/uxvismode.js"></script>
<script type="text/javascript"
src="scripts/ext/ux.media/uxmedia.js"></script>
<script type="text/javascript"
src="scripts/ext/ux.media/uxmedia-ie.js"></script>
<script type="text/javascript"
src="scripts/ext/ux.media/uxflash.js"></script>
<script type="text/javascript"
src="scripts/ext/ux.media/uxchart.js"></script>
<script type="text/javascript"
src="scripts/ext/ux.media/uxofc.js"></script>
</head>
<body>
<p>Hello World ofc2</p>
<div id="div_panel_t"></div>
<div id="div_panel_w"></div>
<div id="div_panel_c">
<div align="center" id="div_iframe">
<div id="div_my_ofc2_chart"></div>
<div id="my_ofc2_chart"></div>
<br>
<div style="text-align: center; font-size: 9pt"><input type="button"
name="btn_control" onclick="changeBtnStatus(this)" value="暂停"></div>
</div>
</div>
</body>
<script type="text/javascript">
var portType = "random";
var portId = "1000";
var portIndex = "5";
var refresh_Interval=10;
var ofc2_chart_id="my_ofc2_chart";
var ofc2_url = '/DrawOfc2RealTimeAction.do';
var flash_param="ofc2_param="+ofc2_chart_id+","+portType+","+portId+","+portIndex;
var obj_refresh = setInterval('refresh_ofc2_chart()', refresh_Interval*1000);
function findSWF(movieName) {
if (navigator.appName.indexOf("Microsoft")!= -1) {
return window[movieName];
} else {
return document[movieName];
}
}
function refresh_ofc2_chart(){
var myAjax = new Ajax.Request(ofc2_url,
{
encoding :'UTF-8',
method :'get',
parameters :flash_param,
asynchronous :false,
onComplete : showResponse
});
}
function showResponse(rep) {
var chartdata = rep.responseText.evalJSON(true);
//var tmp = findSWF(ofc2_chart_id);
//tmp.load(JSON.stringify(chartdata))
var tmp = Ext.getDom(ofc2_chart_id);
tmp.load(Object.toJSON(chartdata));
}
function changeBtnStatus(o_btn){
if(null!=obj_refresh){clearInterval(obj_refresh );}
if("继续"==o_btn.value){
obj_refresh = setInterval('refresh_ofc2_chart()', refresh_Interval*1000);
o_btn.value="暂停";
}else{
o_btn.value="继续";
}
}
function createExtOFC2Comp(_ofc2_id){
var _ux_OFC_Comp = new Ext.ux.Chart.OFC.Component({
height : 300,
width : 500,
renderTo: 'div_'+_ofc2_id,
chartCfg:{
id : _ofc2_id,
autoSize : true,
renderOnResize : false,
disableCaching : true
}
//,mediaMask : {msg:'Loading OpenChart Object'}
,loadMask : {msg:'Gathering Chart Data'}
,autoMask : true
,id :'demoOFC'
,chartURL : 'ofc2/open-flash-chart.swf'
/* Chart data loading options */
//,chartData : data //initial load - pre-defined JSON series
,dataURL : ofc2_url+'?'+flash_param // SWF-Managed remote request in JSON format
,previews : new Array()
});
return _ux_OFC_Comp;
}
Ext.onReady(function() {
var west_panel = new Ext.Panel( {
region : 'west',
id: "sidebar",
split : true,
width : 180,
minSize : 100,
maxSize : 200,
title : " ",
items : [],
autoScroll : true,
collapsible : true,
frame : true
});
var _ofc2_comp = createExtOFC2Comp(ofc2_chart_id);
//_ofc2_comp.show();
var viewport = new Ext.Viewport( {
id : 'hxlayout',
layout : 'border',
layoutConfig : {
animate : true
},
defaults : {
border : false,
split : false
},
items : [
{
region : 'north',
id : 'cmp_panel_t',
contentEl : 'div_panel_t',
height : 40
},west_panel,{
region : 'center',
id : 'top_cmp_panel_c',
contentEl : 'div_panel_c',
autoScroll : true,
items:[_ofc2_comp]
}
]
});
});
</script>
</html>
效果图如下:
【四】动态曲线的简单demo代码
实时流量动态图的效果如上,基本实现的代码如下,demo是个随机数模拟流量的(有关snmp采集端口流量的代码就不在这里贴出了
):
FlowChart2Vo .java
/**
* @author michael
*
*/
public class FlowChart2Vo implements Serializable {
/**
* serialVersionUID
*/
private static final long serialVersionUID = -8305542118777147896L;
private String dataKey;
private String chartId;
private double outLastValue;
private double inLastValue;
private long outLastTime;
private long inLastTime;
private int maxDataCount = 10;
private Double ymax = 1d;
private CommunityTarget target = null;
private String portIndex;
private List<String> xlabelList = new ArrayList<String>();
private List<Double> inFlowList = new ArrayList<Double>();
private List<Double> outFlowList = new ArrayList<Double>();
/**
* @param inFlow
* @param outFlow
* @param xlabel
*/
public void addFlowData(Double inFlow, Double outFlow, String xlabel) {
if (this.inFlowList.size() > this.maxDataCount) {
this.inFlowList.remove(0);
this.outFlowList.remove(0);
this.xlabelList.remove(0);
}
this.inFlowList.add(inFlow);
this.outFlowList.add(outFlow);
this.xlabelList.add(xlabel);
}
/**
* @return
*/
public Double getMaxOutFlow() {
List<Double> temp = new ArrayList<Double>();
for (Double dou : outFlowList) {
if (null != dou && !Double.isNaN(dou)) {
temp.add(dou);
}
}
Collections.sort(temp);
if (temp.size() < 1) {
return 0d;
}
return temp.get(temp.size() - 1);
}
/**
* @return
*/
public Double getMaxInFlow() {
List<Double> temp = new ArrayList<Double>();
for (Double dou : inFlowList) {
if (null != dou && !Double.isNaN(dou)) {
temp.add(dou);
}
}
Collections.sort(temp);
if (temp.size() < 1) {
return 0d;
}
return temp.get(temp.size() - 1);
}
//get set方法省略
//.........
DrawOfc2RealTimeDemoAction.java
package michael.ofc2.action;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jofc2.model.Chart;
import jofc2.model.Text;
import jofc2.model.axis.XAxis;
import jofc2.model.axis.YAxis;
import jofc2.model.elements.LineChart;
import jofc2.model.elements.LineChart.Dot;
import michael.ofc2.vo.FlowChart2Vo;
import org.apache.commons.lang.StringUtils;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.snmp4j.CommunityTarget;
/**
* Open flash chart 2
* @author Michael sun
*/
public class DrawOfc2RealTimeDemoAction extends Action {
/**
* draw chart
* @param mapping struts mapping
* @param form struts form
* @param request http request
* @param response http response
* @return action forward
* @throws Exception any execption
*/
@SuppressWarnings("unchecked")
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.setContentType("application/json");
response.setHeader("Cache-Control", "no-cache");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String ofc2_param = request.getParameter("ofc2_param");
String[] params = ofc2_param.split(",");
String chartId = params[0];// request.getParameter("ofcChartId");
String flashType = params[1];
String equId = params[2];// request.getParameter("equId");
String portIndex = params[3];// request.getParameter("portIndex");
String maxDataCount = null;
if (params.length > 4) {
maxDataCount = params[4];// request.getParameter("maxDataCount");
}
String dataKey = equId + "-" + portIndex;
Map<String, FlowChart2Vo> rtdataMap = (Map<String, FlowChart2Vo>) request
.getSession().getAttribute("SE_FLOW_RTDATA_MAP");
if (null == rtdataMap) {
rtdataMap = new HashMap<String, FlowChart2Vo>();
}
FlowChart2Vo rtDatavo = rtdataMap.get(dataKey);
if (null == rtDatavo) {
rtDatavo = new FlowChart2Vo();
rtDatavo.setDataKey(dataKey);
rtDatavo.setChartId(chartId);
rtDatavo.setPortIndex(portIndex);
CommunityTarget target = null;
rtDatavo.setTarget(target);
}
if (null != maxDataCount && !"".equals(maxDataCount)) {
rtDatavo.setMaxDataCount(Integer.parseInt(maxDataCount));
}
if ("random".equals(flashType)) {
this.getRandomData(rtDatavo);
} else if (StringUtils.isNotEmpty(rtDatavo.getPortIndex())) {
this.getSnmpFlowData(rtDatavo);
}
rtdataMap.put(dataKey, rtDatavo);
request.getSession().setAttribute("SE_FLOW_RTDATA_MAP", rtdataMap);
String chartString = this.createLineChart(rtDatavo);
System.out.println(chartString);
out.write(chartString);
out.close();
return null;
}
/**
* 随机数
* @param rtDatavo
*/
private void getRandomData(FlowChart2Vo rtDatavo) {
String xlabel = getFormatDate(new Date(), "mm:ss");
double inSpeed = 2 + Math.random() * 3;
double outSpeed = 1 + Math.random() * 3;
rtDatavo.addFlowData(inSpeed, outSpeed, xlabel);
}
/**
* snmp 采集端口的出入速率
* @param rtDatavo
*/
private void getSnmpFlowData(FlowChart2Vo rtDatavo) {
// ......
}
/**
* 生成ofc2的json格式数据
* @param rtDatavo
* @return
*/
private String createLineChart(FlowChart2Vo rtDatavo) {
Chart ofc2Chart = new Chart();
Text title = new Text("demo");
ofc2Chart.setTitle(title);
ofc2Chart.setXLegend(new Text("time", "{color: #736AFF;}"));
ofc2Chart.setYLegend(new Text("Flow(Mb/s)", "{color: #736AFF;}"));
LineChart lineChartIn = new LineChart();
lineChartIn.setColour("#00FF00");
lineChartIn.setText("in");
LineChart lineChartOut = new LineChart();
lineChartOut.setColour("#0000FF");
lineChartOut.setText("out");
List<Double> inFlowList = rtDatavo.getInFlowList();
List<Double> outFlowList = rtDatavo.getOutFlowList();
List<String> xlabelList = rtDatavo.getXlabelList();
if (inFlowList.size() > 0 && outFlowList.size() > 0) {
double tmpymax = Math.max(rtDatavo.getMaxInFlow(), rtDatavo
.getMaxOutFlow());
if (tmpymax > rtDatavo.getYmax()) {
rtDatavo.setYmax(tmpymax);
}
}
double ymax = rtDatavo.getYmax();
YAxis y = new YAxis(); // y 轴
y.setMax(ymax); // y 轴最大值
y.setSteps(ymax / 10); // y 轴步进
XAxis xaxis = new XAxis(); // X 轴
for (int i = 0; i < inFlowList.size(); i++) {
xaxis.addLabels(xlabelList.get(i));
Dot indot = new Dot(inFlowList.get(i));
indot.setDotSize(2);
indot.setHaloSize(2);
lineChartIn.addDots(indot);
Dot dot2 = new Dot(outFlowList.get(i));
dot2.setDotSize(2);
dot2.setHaloSize(2);
lineChartOut.addDots(dot2);
}
ofc2Chart.addElements(lineChartIn);
ofc2Chart.addElements(lineChartOut);
ofc2Chart.setXAxis(xaxis);
ofc2Chart.setYAxis(y);
return ofc2Chart.toString();
}
/**
* 将日期(Date形式)按格式转化成日期(String形式).
* @param date 日期(Date形式)
* @param formatStr 日期格式
* @return dateStr 日期(String形式)
*/
public static String getFormatDate(Date date, String formatStr) {
String dateStr = "";
SimpleDateFormat sdf = new SimpleDateFormat(formatStr, Locale.UK);
dateStr = sdf.format(date);
return dateStr;
}
}
-----------------------------------分 ------------------------------------隔 ------------------------------------线 --------------------------------------