前言

FineReport除了内置的图表、新特性图表插件外,还提供了第三方图表开发的API,方便进行个性化、第三方的图表开发。但是第三方图表API接口过于复杂,用户很难快速的实现并使用自己想使用的第三方新图表。

解决方法

在原有的图表接口基础之上,对接口进行了简化和修改,让用户可以快速的写出第三方图表插件并使用。

关键接口

插件图表接口

 

package com.fr.chart.fun;

import com.fr.chart.chartattr.Chart;
import com.fr.stable.fun.Level;

/**
 * Created by eason on 15/4/21.
 * 图表接口
 */
public interface IndependentChartProvider extends Level {

 String XML_TAG = "IndependentChartProvider";

 int CURRENT_API_LEVEL = 3;

 /**
 * 图表的国际化的名字的key
 *
 * @return 图表国际化的名字的key
 */
 String getChartName();

 /**
 * 该种图表所有的图表类型,比如柱形图就有堆积柱形图,百分比堆积柱形图等等
 *
 * @return 所有的图表类型
 */
 Chart[] getChartTypes();

 /**
 * 图表在web端展现时需要的JS文件
 *
 * @return JS文件数组
 */
 String[] getRequiredJS();

 /**
 * JS对象名,该对象一般是一个函数,执行后会在给定的dom中绘制图表
 *
 * @return JS对象名
 */
 String getWrapperName();

 /**
 * 定义在设计器里展现的图的路径
 *
 * @return 图的路径
 */
 String getChartImagePath();
/**
 * 当前接口的API等级,用于判断是否需要升级插件
 *
 * @return API等级
 */
int currentAPILevel();

}

上述接口您不必实现,只需要继承实现了该接口的抽象类:AbstractIndependentChartProvider4Custom类即可,并实现里面具体的方法,示例如下:

package com.fr.plugins.democharts.pie;

import com.fr.chart.chartattr.Chart;
import com.fr.chart.fun.impl.AbstractIndependentChartProvider4Custom;


public class DemoChartsPie extends AbstractIndependentChartProvider4Custom {

    public static pieChart[] charts = new pieChart[] {
            new pieChart(),
    };


    @Override
    public String getChartName() {
        return "用户自定义图表";
    }

    @Override
    public String[] getRequiredJS() {
        return new String[]{
                "/com/fr/plugins/democharts/common/web/echarts.bridge.js"
        };
    }

    @Override
    public String getWrapperName() {
        return "EChartsFactory";
    }

    @Override
    public Chart[] getChartTypes() {
        return charts;
    }

    @Override
    public String getChartImagePath() {
        return "com/fr/plugins/democharts/pie/images/pie256.png";
    }
	@Override
	public int currentAPILevel() {
   	 	return CURRENT_API_LEVEL;
	}
}

 

插件图表界面接口

 

package com.fr.design.chart.fun;

/**
 * Created by eason on 14/12/29.
 *
 * @since 8.0
 * 自定义图表类型设设计界面接口
 */
public interface IndependentChartUIProvider extends Level {

 String XML_TAG = "IndependentChartUIProvider";

 int CURRENT_API_LEVEL = 3;


/**
 * 当前接口的API等级,用于判断是否需要升级插件
 *
 * @return API等级
 */
int currentAPILevel();
 /**
 * 图表配置面板
 *
 * @return图表配置面板
 */
 ThirdChartConfigPane getChartConfigPane(String plotID);

 ......(其他方法不用实现)
}

此接口您不必实现 ,只需要继承实现了该接口的抽象类: AbstractIndependentChartUI4Custom 类即可,并实现相应方法,示例如下:

package com.fr.plugins.democharts.pie;

import com.fr.design.chart.fun.impl.AbstractIndependentChartUI4Custom;
import com.fr.design.mainframe.chart.ChartEditPane;


public class DemoChartsPieUI extends AbstractIndependentChartUI4Custom {
    @Override
	public ThirdChartConfigPane getChartConfigPane(String plotID) {
    	return new ChartConfigPane();
	}

    @Override
    public int currentAPILevel() {
        return CURRENT_API_LEVEL;
    }
}

关键抽象类

图表配置面板类

package com.fr.design.mainframe.chart;

import com.fr.chart.chartattr.ChartCollection;
import com.fr.general.Inter;

import javax.swing.*;

/**
 * Created by mengao on 2017/5/16.
 */
public class ThirdChartConfigPane extends AbstractChartAttrPane {

    public final static String CHART_STYLE_TITLE = Inter.getLocText("Chart-Style_Name");

    @Override
    public void populate(ChartCollection collection) {

    }

    @Override
    public void update(ChartCollection collection) {

    }

    @Override
    protected JPanel createContentPane() {
        return new JPanel();
    }

    @Override
    public String getIconPath() {
        return "com/fr/design/images/chart/ChartStyle.png";
    }

    @Override
    public String title4PopupWindow() {
        return CHART_STYLE_TITLE;
    }
}

 

您的图表配置面板需要继承此抽象类,并实现相应的方法,示例如下:
 package com.fr.plugins.democharts.commenDataPie;

import com.fr.chart.chartattr.ChartCollection;
import com.fr.design.mainframe.chart.ThirdChartConfigPane;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * Created by mengao on 2017/4/26.
 * 图表样式面板,需要继承ThirdChartConfigPane
 * 需要实现方法:populate
 * 需要实现方法:update
 */
public class ChartConfigPane extends ThirdChartConfigPane {
    private ChartCollection chartCollection;
    JPanel northJpane = new JPanel();
    JPanel centerJpane = new JPanel();
    JLabel nameJLable = new JLabel("请输入内容:");
    JTextField value = new JTextField();
    JButton updateButton = new JButton("确定");

    public ChartConfigPane() //构造方法
    {
        this.setLayout(new BorderLayout());
        northJpane.setLayout(new GridLayout(3, 2));
        northJpane.add(nameJLable);
        northJpane.add(value);
        this.add(northJpane, BorderLayout.NORTH);
        centerJpane.add(updateButton, BorderLayout.CENTER);
        this.add(centerJpane, BorderLayout.CENTER);
        this.setSize(200, 200);
        this.setVisible(true);
        updateButton.addActionListener(new ColorEventListener());
    }

    @Override
    public void populate(ChartCollection collection) {
        if (collection.getSelectedChart() instanceof pieChart) {
            this.chartCollection = collection;
            pieChart pieChart = (pieChart) collection.getSelectedChart();
            value.setText(pieChart.getCustomData());
        }
    }

    @Override
    public void update(ChartCollection collection) {
        if (collection.getSelectedChart() instanceof pieChart) {
            pieChart pieChart = (pieChart) collection.getSelectedChart();
            pieChart.setCustomData(value.getText());
        }
    }

    // 内部类EventListener,实现ActionListener接口
    class ColorEventListener implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {
            update(chartCollection);
        }
    }


}




图表类

package com.fr.chart.chartattr;
 

/**
 * Created by mengao on 2017/5/3.
 * 用户使用第三方图表需要继承chart父类
 */
public abstract class ThirdChart extends Chart  {
    protected ChartData ChartData;

    public ChartData getChartData() {
        return ChartData;
    }

    public void setChartData(ChartData chartData) {
        ChartData = chartData;
    }

    protected abstract String getChartID();

    public ThirdChart() {
        ThirdChartPlot thirdChartPlot = new ThirdChartPlot();
        thirdChartPlot.setPlotID(getChartID());
        this.setPlot(thirdChartPlot);
    }

    @Override
    public BaseChartGlyph createGlyph(ChartData chartData) {
        ChartGlyph chartGlyph = new ChartGlyph(){
            public JSONObject toJSONObject(Repository repo, double width, double height) throws JSONException {
            return toJSON(repo);
            }
        };

        setChartData(chartData);
        chartGlyph.setWrapperName(this.getWrapperName());
        chartGlyph.setRequiredJS(this.getRequiredJS());
        chartGlyph.setChartImagePath(this.getImagePath());

        return chartGlyph;
    }
    public abstract JSONObject toJSON (Repository repo) throws JSONException;
}

 

您的图表配置面板ChartConfig类需要继承此抽象类,并实现相应方法,示例如下:

 

package com.fr.plugins.democharts.commenDataPie;

import com.fr.chart.chartattr.ThirdChart;
import com.fr.chart.chartdata.NormalChartData;
import com.fr.json.JSONArray;
import com.fr.json.JSONException;
import com.fr.json.JSONObject;
import com.fr.stable.web.Repository;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLableReader;


/**
 * Created by mengao on 2017/4/26.
 * chart类,需要继承ThirdChart
 * 需要实现方法:getChartID
 * 需要实现方法:writeXML
 * 需要实现方法:readXML
 * 需要实现方法:toJSON
 */
public class pieChart extends ThirdChart {
    private String customData= "公共数据配置面板demo";

    public String getCustomData() {
        return customData;
    }

    public void setCustomData(String customData) {
        this.customData = customData;
    }

    @Override
    public void writeXML(XMLPrintWriter xmlPrintWriter) {
        super.writeXML(xmlPrintWriter);
        xmlPrintWriter.startTAG("customChartDemo")
                .attr("custom", getCustomData())
                .end();
    }

    @Override
    public void readXML(XMLableReader xmLableReader) {
        super.readXML(xmLableReader);
        if (xmLableReader.isChildNode()) {
            String tagName = xmLableReader.getTagName();
            if(tagName.equals("customChartDemo")) {
                setCustomData(xmLableReader.getAttrAsString("custom","111"));
            }
        }
    }

    /**
     * 读出字符串,然后传到前台
     * 注意:需要获取数据配置中的数据,使用getChartData()方法
     */
    @Override
    //tojson的时候注意用getChartData()方法获取当前数据集,然后自主拼接成json
    public JSONObject toJSON(Repository repo) throws JSONException {
        //用默认的  NormalChartData 进行数据配置
        JSONObject jsonObject = new JSONObject();
        if (this.getChartData() instanceof NormalChartData) {
            NormalChartData normalChartData = (NormalChartData) this.getChartData();
            JSONArray series = JSONArray.create();

            int len = normalChartData.getCategory_array().length;//获取分类数组的长度
            int cn = normalChartData.getSeries_array().length;//获取系列数组的长度
            for (int c = 0; c < cn; c++) {
                //对系系列循环
                JSONObject wrapper = JSONObject.create();
                series.put(wrapper);

                JSONArray point = JSONArray.create();
                wrapper.put("type", "pie");
                //将每个系类值给data
                wrapper.put("data", point);
                if (c == 1) {
                    int[] radius = {20,110};
                    String[] center = {"25%", "50%"};
                    wrapper.put("radius", radius);
                    wrapper.put("center", center);
                }else{
                    int[] radius = {30,110};
                    String[] center = {"75%", "50%"};
                    wrapper.put("radius", radius);
                    wrapper.put("center", center);
                }
                //将系列名给系列
                wrapper.put("name", normalChartData.getSeries_array()[c].toString());
                for (int i = 0; i < len; i++) {
                    //
                    String name = normalChartData.getCategory_array()[i].toString();
                    JSONObject item = JSONObject.create();
                    point.put(item);
                    //将分类名给name
                    item.put("name", name);
                    if (normalChartData.getSeries_value_2D().length > 0) {
                        //将点的值给data
                        item.put("value",normalChartData.getSeries_value_2D()[c][i]);
                    }
                }
            }

            jsonObject.put("series", series);
            JSONObject title=new JSONObject();
            title.put("text",getCustomData());
            jsonObject.put("title",title);

        }
        return jsonObject;
    }


    @Override
    public String getChartID() {
        return "CommenDataDemoChartsPie";
    }


}


XML关键配置

 

<extra-core>
    <JavaScriptFileHandler class="com.fr.plugins.democharts.common.web.EChartsFileLoader"/>
</extra-core>
<extra-chart>
 <IndependentChartProvider class="com.fr.plugins.democharts.pie.DemoChartsPie"
 plotID="DemoChartsPiePlot"/>
</extra-chart>
<extra-chart-designer>
 <IndependentChartUIProvider class="com.fr.plugins.democharts.pie.DemoChartsPieUI"
 plotID="DemoChartsPiePlot"/>
</extra-chart-designer>

简单效果图

您可以自定义图表属性配置面板,更加灵活。

通过配置面板配置好数据后,您可以预览您图表配置好之后的效果,demo展示效果如下:

示例源码

如果您希望看示例源码,您可以看这里: