结合AnyChart做报表:一个生成AnyChart图形XML数据的工具类

今天头有点痛,所以不能详细地写了,先把代码贴上来,等身体状况稍微好一点,再继续完善。

1、(主角)一个使用XML模板生成Anychart XML数据的工具类

/**
 * 
 */
package com.common.anychart;

import java.io.InputStream;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.common.reflect.ReflectUtils;

/**
 * XML数据处理工具类,服务于AnyChart报表
 * @author luolin
 *
 * @version $id:AnyChartXMLProcessor.java,v 0.1 2015年8月19日 上午10:15:57 luolin Exp $
 */
public class AnyChartXMLProcessor {

    private static final Logger LOGGER                         = Logger
                                                                   .getLogger(AnyChartXMLProcessor.class);

    /** 简单线性曲线图模板路径 */
    private static final String SIMPLE_LINE_TEMPLATE_FILE      = "xmltemplate/simpleLine.xml";
    /** 简单柱状图图模板路径 */
    private static final String SIMPLE_HISTOGRAM_TEMPLATE_FILE = "xmltemplate/simpleHistogram.xml";

    /**
     * 使用simpleLine.xml模板生成简单的线性曲线图XML数据
     * @param xName x轴标题,格式如:“X轴标题@feild”,feild表示从数据中取值的字段
     * @param yName y轴标题,格式如:“y轴标题@feild”,feild表示从数据中取值的字段
     * @param title 图标标题
     * @param dataList 要展示的数据
     * @return 生成的XML数据
     * @throws Exception 
     */
    public static String simpleLine(String xName, String yName, String title, List<?> dataList)
                                                                                               throws Exception {
        LOGGER.info("【使用categorizedVertical.xml模板生成简单的线性曲线图XML数据】xName : " + xName + " , yName : "
                    + yName + " , title : " + title);
        // 基本参数校验
        if (!baseDataValidate(xName, yName, title, dataList)) {
            return "";
        }
        String[] xData = xName.split("@");
        String[] yData = yName.split("@");
        // 坐标轴数据校验
        axisFormatValidate(xData, yData);

        InputStream inputStream = AnyChartXMLProcessor.class.getClassLoader().getResourceAsStream(
            SIMPLE_LINE_TEMPLATE_FILE);

        return templateProcessor(title, dataList, xData, yData, inputStream);
    }

    /**
     * 根据模板处理数据,生成修改后的XML数据
     * @param title 统计图的标题
     * @param dataList 统计数据
     * @param xData X轴数据
     * @param yData Y轴数据
     * @param inputStream 读入模板的流
     * @return 修改模板后得到的XML数据
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    private static String templateProcessor(String title, List<?> dataList, String[] xData,
                                            String[] yData, InputStream inputStream)
                                                                                    throws Exception {
        SAXReader sax = new SAXReader();
        Document xmlDoc = sax.read(inputStream);
        Element root = xmlDoc.getRootElement();//根节点  
        // 取得text节点
        List<Element> titleElements = root.selectNodes("//text");
        // 得到chart_settings下的第一个text节点,并修改它的值
        Element titleElement = titleElements.get(0);
        titleElement.setText(title);

        // 得到X轴的第一个text坐标,修改它的值
        Element xTitleElement = titleElements.get(1);
        xTitleElement.setText(xData[0]);

        // 得到X轴的第一个text坐标,修改它的值
        Element yTitleElement = titleElements.get(2);
        String yTitleTemplate = yTitleElement.getTextTrim();
        yTitleElement.setText(yTitleTemplate.replace("#YTitle#", yData[0]));

        // 替换format里面的x、y的标题
        List<Element> formatElements = root.selectNodes("//format");
        if (CollectionUtils.isNotEmpty(formatElements)) {
            for (Element element : formatElements) {
                String formatText = element.getTextTrim();
                element.setText(formatText.replace("#YTitle#", yData[0]).replace("#XTitle#",
                    xData[0]));
            }
        }

        Element dataElement = (Element) root.selectSingleNode("//data");
        // 如何数据集里存放的是更多数据集(表示需要多条线或者多柱),循环处理
        if (dataList.get(0) instanceof List) {
            for (Object element : dataList) {
                createSeriesElement(title, (List<?>) element, xData, yData, dataElement);
            }
            return xmlDoc.asXML();
        }
        createSeriesElement(title, dataList, xData, yData, dataElement);
        return xmlDoc.asXML();
    }

    /**
     * 生成series部分
     * @param title 标题
     * @param dataList 数据集合
     * @param xData X轴数据
     * @param yData Y轴数据
     * @param dataElement "data"节点
     * @throws Exception
     */
    private static void createSeriesElement(String title, List<?> dataList, String[] xData,
                                            String[] yData, Element dataElement) throws Exception {
        Element seriesElement = dataElement.addElement("series");
        seriesElement.addAttribute("name", title);
        for (Object item : dataList) {
            Element pointElement = seriesElement.addElement("point");
            pointElement.addAttribute("name",
                String.valueOf(ReflectUtils.getCellValue(item, xData[1])));
            pointElement.addAttribute("y",
                String.valueOf(ReflectUtils.getCellValue(item, yData[1])));
        }
    }

    /**
     * 坐标轴数据校验
     * @param xData X轴信息
     * @param yData Y轴信息
     */
    private static void axisFormatValidate(String[] xData, String[] yData) {
        if (xData.length < 2) {
            LOGGER.warn("【xName参数不正确】xData : " + xData);
            throw new IllegalArgumentException("xName");
        }
        if (yData.length < 2) {
            LOGGER.warn("【yName参数不正确】yData : " + yData);
            throw new IllegalArgumentException("yName");
        }
    }

    /**
     * 基本数据校验
     * @param xName x轴标题,格式如:“X轴标题@feild”,feild表示从数据中取值的字段
     * @param yName y轴标题,格式如:“y轴标题@feild”,feild表示从数据中取值的字段
     * @param title 图标标题
     * @param dataList 要展示的数据
     */
    private static boolean baseDataValidate(String xName, String yName, String title,
                                            List<?> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            LOGGER.warn("【数据dataList为空】");
            return false;
        }
        if (StringUtils.isBlank(xName)) {
            LOGGER.warn("【xName为空】");
            throw new NullArgumentException("xName");
        }
        if (StringUtils.isBlank(yName)) {
            LOGGER.warn("【yName为空】");
            throw new NullArgumentException("yName");
        }
        if (StringUtils.isBlank(title)) {
            LOGGER.warn("【title为空】");
            throw new NullArgumentException("title");
        }
        return true;
    }

    /**
     * 使用simpleHistogram.xml模板生成简单的柱状图的XML数据
     * @param xName x轴标题,格式如:“X轴标题@feild”,feild表示从数据中取值的字段
     * @param yName y轴标题,格式如:“y轴标题@feild”,feild表示从数据中取值的字段
     * @param title 图标标题
     * @param dataList 要展示的数据
     * @return 生成的XML数据
     * @throws Exception 
     */
    public static String simpleHistogram(String xName, String yName, String title, List<?> dataList)
                                                                                                    throws Exception {

        LOGGER.info("【使用simpleHistogram.xml模板生成简单的柱状图的XML数据】xName : " + xName + " , yName : "
                    + yName + " , title : " + title);
        // 基本参数校验
        if (!baseDataValidate(xName, yName, title, dataList)) {
            return "";
        }
        String[] xData = xName.split("@");
        String[] yData = yName.split("@");
        // 坐标轴数据校验
        axisFormatValidate(xData, yData);

        InputStream inputStream = AnyChartXMLProcessor.class.getClassLoader().getResourceAsStream(
            SIMPLE_HISTOGRAM_TEMPLATE_FILE);

        return templateProcessor(title, dataList, xData, yData, inputStream);
    }

    /**
     * 使用simpleHistogram.xml模板生成简单的多柱柱状图的XML数据
     * @param xName x轴标题,格式如:“X轴标题@feild”,feild表示从数据中取值的字段
     * @param yName y轴标题,格式如:“y轴标题@feild”,feild表示从数据中取值的字段
     * @param title 图标标题
     * @param dataList 要展示的数据
     * @return 生成的XML数据
     * @throws Exception
     */
    public static String compareHistogram(String xName, String yName, String title,
                                          List<List<?>> dataList) throws Exception {
        LOGGER.info("【使用simpleHistogram.xml模板生成简单的多柱柱状图的XML数据】xName : " + xName + " , yName : "
                    + yName + " , title : " + title);
        // 基本参数校验
        if (!baseDataValidate(xName, yName, title, dataList)) {
            return "";
        }
        String[] xData = xName.split("@");
        String[] yData = yName.split("@");
        // 坐标轴数据校验
        axisFormatValidate(xData, yData);

        InputStream inputStream = AnyChartXMLProcessor.class.getClassLoader().getResourceAsStream(
            SIMPLE_HISTOGRAM_TEMPLATE_FILE);
        return templateProcessor(title, dataList, xData, yData, inputStream);
    }

}


2015-8-27 09:26:11更新:昨天忘记添加其中用到的一个反射工具类的代码,今天补上:

ReflectUtils.java

/**
 * 
 */
package com.common.reflect;

import java.lang.reflect.Field;

/**
 * 反射工具类
 * @author luolin
 *
 * @version $id:ReflectUtils.java,v 0.1 2015年8月19日 下午1:46:54 luolin Exp $
 */
public class ReflectUtils {

    /**
     * 通过字段名从对象中得到字段的值
     * @param object 对象
     * @param fieldName 字段名
     * @return 字段对应的值
     * @throws Exception
     */
    public static Object getCellValue(Object object, String fieldName) throws Exception {
        Field[] fields = object.getClass().getDeclaredFields();
        Object value = null;
        for (Field field : fields) {
            field.setAccessible(true);
            if (field.getName().equals(fieldName)) {
                value = field.get(object);
                break;
            }
        }
        return value;
    }

}




2、模板文件:目前我使用了两个简单的模板文件。朋友们在使用的时候,注意模板相对工程的路径需要根据实际情况修改。

折线图模板(simpleLine.xml):

<anychart>
	<settings>
		<animation enabled="True"/>
	</settings>
	<charts>
		<chart plot_type="CategorizedVertical">
			<chart_settings>
				<title enabled="true">
					<text>标题未初始化</text>
				</title>
				<axes>
					<x_axis tickmarks_placement="Center">
						<labels enabled="true"  rotation="60" display_mode="rotated" align="Inside">  
						</labels>  
						<title enabled="true">
							<text>#XTitle#</text>
						</title>
					</x_axis>
					<y_axis>
						<title enabled="true">
							<text>#YTitle#:  {%Min} - {%Max}</text>
						</title>
					</y_axis>
				</axes>
			</chart_settings>
			<data_plot_settings default_series_type="Line">
				<line_series point_padding="0.2" group_padding="1">
					<label_settings enabled="true">
						<background enabled="false"/>
						<font color="Rgb(45,45,45)" bold="true" size="9">
							<effects enabled="true">
								<glow enabled="true" color="White" opacity="1" blur_x="1.5" blur_y="1.5" strength="3"/>
							</effects>
						</font>
						<format>{%YValue}{numDecimals:0}</format>
					</label_settings>
					<tooltip_settings enabled="true">
						<format>
							#YTitle#: {%YValue}{numDecimals:2}  
							#XTitle#: {%Name}
						</format>
						<background>
							<border type="Solid" color="DarkColor(%Color)"/>
						</background>
						<font color="DarkColor(%Color)"/>
					</tooltip_settings>
					<marker_settings enabled="true"/>
					<line_style>
						<line thickness="3"/>
					</line_style>
				</line_series>

			</data_plot_settings>
			<data>
			
			</data>
		</chart>
	</charts>
</anychart>



柱状图模板(simpleHistogram.xml):
<anychart>
	<settings>
		<animation enabled="True"/>
	</settings>
	<charts>
		<chart plot_type="CategorizedVertical">
			<chart_settings>
				<title enabled="true">
					<text>标题未初始化</text>
				</title>
				<axes>
					<x_axis tickmarks_placement="Center">
						<labels enabled="true"  rotation="60" display_mode="rotated" align="Inside">  
						</labels>  
						<title enabled="true">
							<text>#XTitle#</text>
						</title>
					</x_axis>
					<y_axis>
						
						<title enabled="true">
							<text>#YTitle#:  {%Min} - {%Max}</text>
						</title>
					</y_axis>
				</axes>
			</chart_settings>
			<data_plot_settings default_series_type="Bar">
				<bar_series group_padding="0.2">
					<tooltip_settings enabled="true">
						<format>
							#YTitle#: {%YValue}{numDecimals:2}  
							#XTitle#: {%Name}
						</format>
						<background>
							<border type="Solid" color="DarkColor(%Color)"/>
						</background>
						<font color="DarkColor(%Color)"/>
					</tooltip_settings>
				</bar_series>
			</data_plot_settings>
			<data>
				
			</data>
		</chart>
	</charts>
</anychart>



3、如何使用?

我是使用AJAX的方式获取XML数据并交给anychart的。

/**
 * 创建图表
 * @param chartDivId 显示图表的DIV的ID
 * @param xmlData 图表需要的XML数据
 */
function createChart(chartDivId,xmlData){
	AnyChart.swfFile = "../js/anychart/AnyChart.swf";
	AnyChart.initText = "初始化中,请稍后...";
	AnyChart.xmlLoadingText = "数据加载中,请稍后...";
	AnyChart.noDataText = "没有数据显示,换个查询条件试试!";
	
	var g_dxzr_chart = new AnyChart();
	g_dxzr_chart.width = '100%';
	g_dxzr_chart.height = '100%';
	g_dxzr_chart.bgColor = "#ffffff";
	g_dxzr_chart.setData(xmlData);
	g_dxzr_chart.write(chartDivId);
}

/**
 * 获取数据
 * @param top3FormId 查询参数的form的ID
 */
function executeAnalyzeTop3(top3FormId,chartDivId){
	var $form = $('#'+top3FormId); 
	$.ajax({
		url:$form.attr('action'),
		data:$form.serialize(),
		dataType:'text',
		type:'post',
		success:function(data){
			// 创建图表
			createChart(chartDivId,data);
		},
		error:function(){
			alert('系统异常,请联系管理员!');
		}
	})
}



大家如果有什么问题的话,可以给我留言,我也是最近才接触到anychart的,效果其实觉得还不错。

大家一起学习进步。




你可能感兴趣的:(java,统计,工具类,anychart)