Open Flash Chart2实现动态曲线图小结

    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>

运行结果示例图:

Open Flash Chart2实现动态曲线图小结_第1张图片

Open Flash Chart2实现动态曲线图小结_第2张图片

Open Flash Chart2实现动态曲线图小结_第3张图片

  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>

运行结果示例图:

Open Flash Chart2实现动态曲线图小结_第4张图片

Open Flash Chart2实现动态曲线图小结_第5张图片

【二】、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>

效果图如下:

Open Flash Chart2实现动态曲线图小结_第6张图片

【四】动态曲线的简单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;
    }
}


-----------------------------------分 ------------------------------------隔 ------------------------------------线 --------------------------------------

你可能感兴趣的:(java,json,Flash,open,曲线图,Chart2)