前言:
6个步骤,7个文件,千行代码, !
要开发一款图表,首先要清楚所用前端库的一些基础接口,此图表类型的数据结构。
以echarts三维柱形图(以下简称DEMO)为例,开发之前要知道:
1.数据结构
x轴数据 | y轴数据 | z轴数据 |
---|
... | ... | ... |
... | .. | ... |
2.前台图表实例化api:echarts.init(dom),配置项api:instance.setOption(option)。
前期准备:
- idea中新建一个模块。
- 在模块src下新建一个文件夹com.fr.plugin,之后在此文件夹下新建各种文件。原因:引擎默认只处理com.fr.plugin(9.0插件)或com.fr(8.0插件)包下的类。
- 将前端库所用js文件拷贝到com.fr.plugin下。
- 理解 开发步骤
开发步骤:栗子是echarts三维柱形图
第一步:
定义图表所需数据结构xxxDataConfig,继承抽象类AbstractDataConfig。
eg :
声明变量x、y、z(保存配置的xyz轴数据的字段名称)。
实现抽象方法:readXML(模板读取)&& writeXML(模板写入)&& clone && equals && hashCode && dataSetFields(返回由声明的变量组成的数组,用于预览时取数据库取数)。
其中,供开发者使用的readExtendedField&writeExtendedField方法的第二个参数是字段写入模板对应的key。
package com.fr.plugin.demo;
import com.fr.extended.chart.AbstractDataConfig;
import com.fr.extended.chart.ExtendedField;
import com.fr.general.ComparatorUtils;
import com.fr.stable.xml.XMLPrintWriter;
import com.fr.stable.xml.XMLableReader;
/**
* Created by shine on 2018/3/24.
*/
public class DemoDataConfig extends AbstractDataConfig {
private ExtendedField x = new ExtendedField();
private ExtendedField y = new ExtendedField();
private ExtendedField z = new ExtendedField();
public ExtendedField getX() {
return x;
}
public void setX(ExtendedField x) {
this.x = x;
}
public ExtendedField getY() {
return y;
}
public void setY(ExtendedField y) {
this.y = y;
}
public ExtendedField getZ() {
return z;
}
public void setZ(ExtendedField z) {
this.z = z;
}
@Override
protected void readAttr(XMLableReader reader) {
readExtendedField(x, "x", reader);
readExtendedField(y, "y", reader);
readExtendedField(z, "z", reader);
}
@Override
protected void writeAttr(XMLPrintWriter writer) {
writeExtendedField(x, "x", writer);
writeExtendedField(y, "y", writer);
writeExtendedField(z, "z", writer);
}
@Override
public ExtendedField[] dataSetFields() {
return new ExtendedField[]{
x,
y,
z
};
}
@Override
public DemoDataConfig clone() throws CloneNotSupportedException {
DemoDataConfig result = new DemoDataConfig();
result.setX(this.getX().clone());
result.setY(this.getY().clone());
result.setZ(this.getZ().clone());
return result;
}
@Override
public int hashCode() {
return super.hashCode() + AssistUtils.hashCode(this.getX(), this.getY(), this.getZ());
}
@Override
public boolean equals(Object obj) {
return obj instanceof DemoDataConfig
&& AssistUtils.equals(this.getX(), ((DemoDataConfig) obj).getX())
&& AssistUtils.equals(this.getY(), ((DemoDataConfig) obj).getY())
&& AssistUtils.equals(this.getZ(), ((DemoDataConfig) obj).getZ())
;
}
}
第二步:
定义前台图表对象xxxWrapper.js,指定图表库的初始图表接口。
eg:demoWrapper
demoWrapper = ExtendedChart.extend({
_init:function (dom, option) {
var chart = echarts.init(dom);
chart.setOption(option);
return chart;
}
});
第三步:
定义后台图表对象xxxChart,继承抽象类AbstractChart。注意点:继承的时候别忘了指定泛型DemoDataConfig,即extends AbstractChart<DemoDataConfig>。
eg:
实现抽象方法:getChartID (图表标志ID)&& getChartName(图表名称) && demoImagePath (图表选择界面图片路径) && addJSON (预览时生成的json对象,即图表展现所需配置项option && requiredJS (前端图表库js文件)&& wrapperName(前端图表对象,即第二步定义的对象名称)。
其中,获取某字段对应的数据库数据使用方法dataConfig.getX().getValues())。
package com.fr.plugin.extended.chart.demo;
import com.fr.base.BaseFormula;
import com.fr.extended.chart.AbstractChart;
import com.fr.extended.chart.HyperLinkPara;
import com.fr.extended.chart.export.ExportProcessor;
import com.fr.general.GeneralUtils;
import com.fr.json.JSON;
import com.fr.json.JSONArray;
import com.fr.json.JSONException;
import com.fr.json.JSONFactory;
import com.fr.json.JSONObject;
import com.fr.stable.web.Repository;
import java.util.List;
/**
* Created by shine on 2018/3/24.
*/
public class DemoChart extends AbstractChart<DemoDataConfig>{
private static final String ID = "DEMO_CHART";
private static final String NAME = "DEMO图表";
@Override
protected String getChartID() {
return ID;
}
@Override
public String getChartName() {
return NAME;
}
@Override
protected String demoImagePath() {
return "com/fr/plugin/extended/chart/demo/demo.png";
}
@Override
protected void addJSON(DemoDataConfig dataConfig, JSONObject jsonObject, Repository repo, JSONPara para) throws JSONException {
JSONArray array = JSONFactory.createJSON(JSON.ARRAY);
List<Object> xValues = dataConfig.getX().getValues();
List<Object> yValues = dataConfig.getY().getValues();
List<Object> zValues = dataConfig.getZ().getValues();
double maxValue = Double.MIN_VALUE;
for (int i = 0, len = xValues.size(); i < len; i++) {
maxValue = Math.max(GeneralUtils.objectToNumber(zValues.get(i)).doubleValue(), maxValue);
array.put(JSONFactory.createJSON(JSON.ARRAY).put(xValues.get(i)).put(yValues.get(i)).put(zValues.get(i)));
}
jsonObject.put("series", JSONFactory.createJSON(JSON.OBJECT).put("type", "bar3D").put("data", array)
.put("bevelSize", 0.2).put("bevelSmoothness", 2).put("shading", "color"));
jsonObject.put("xAxis3D", JSONFactory.createJSON(JSON.OBJECT).put("type", "category"))
.put("yAxis3D", JSONFactory.createJSON(JSON.OBJECT).put("type", "category"))
.put("zAxis3D", JSONFactory.createJSON(JSON.OBJECT).put("type", "value"));
jsonObject.put("grid3D", JSONFactory.createJSON(JSON.OBJECT).put("boxWidth", 200).put("boxDepth", 80));
jsonObject.put("visualMap", JSONFactory.createJSON(JSON.OBJECT)
.put("max", maxValue)
.put("color", JSONFactory.createJSON(JSON.ARRAY).put("#d94e5d").put("#eac736").put("#50a3ba")));
}
@Override
protected String[] requiredJS() {
return new String[]{
"com/fr/plugin/extended/chart/demo/demoWrapper.js",
"com/fr/plugin/extended/chart/demo/echarts.js",
"com/fr/plugin/extended/chart/demo/echarts-gl.js"
};
}
@Override
protected String wrapperName() {
return "demoWrapper";
}
@Override
protected HyperLinkPara[] hyperLinkParas() {
return new HyperLinkPara[0];
}
@Override
protected List<StringFormula> formulas() {
return null;
}
@Override
protected ExportProcessor createExportProcessor() {
return null;
}
}
第四步:数据界面。
数据集数据界面xxxTableDataPane,继承抽象类AbstractExtendedChartTableDataPane。注意点:extends AbstractExtendedChartTableDataPane<DemoDataConfig>
eg:
声明变量下拉框 x、y、z。
实现抽象方法:fieldLabels (标签名称)&& filedComboBoxes (下拉框数组)&& populate (属性设置到界面组件)&& update(组件值保存到图表属性中)。
package com.fr.plugin.extended.chart.demo;
import com.fr.design.gui.icombobox.UIComboBox;
import com.fr.extended.chart.AbstractExtendedChartTableDataPane;
/**
* Created by shine on 2018/3/24.
*/
public class DemoTableDataPane extends AbstractExtendedChartTableDataPane<DemoDataConfig>{
private UIComboBox xComboBox;
private UIComboBox yComboBox;
private UIComboBox zComboBox;
@Override
protected String[] fieldLabels() {
return new String[]{
"X轴",
"Y轴",
"Z轴"
};
}
@Override
protected UIComboBox[] filedComboBoxes() {
if (xComboBox == null) {
xComboBox = new UIComboBox();
yComboBox = new UIComboBox();
zComboBox = new UIComboBox();
}
return new UIComboBox[]{
xComboBox,
yComboBox,
zComboBox
};
}
@Override
protected void populate(DemoDataConfig dataConf) {
populateField(xComboBox, dataConf.getX());
populateField(yComboBox, dataConf.getY());
populateField(zComboBox, dataConf.getZ());
}
@Override
protected DemoDataConfig update() {
DemoDataConfig dataConfig = new DemoDataConfig();
updateField(xComboBox, dataConfig.getX());
updateField(yComboBox, dataConfig.getY());
updateField(zComboBox, dataConfig.getZ());
return dataConfig;
}
}
单元格配置界面xxxReportDataPane,继承抽象类AbstractExtendedChartReportDataPane。处理参考数据集数据配置界面,上栗子,不做累述。
package com.fr.plugin.extended.chart.demo;
import com.fr.design.formula.TinyFormulaPane;
import com.fr.extended.chart.AbstractExtendedChartReportDataPane;
/**
* Created by shine on 2018/3/24.
*/
public class DemoReportDataPane extends AbstractExtendedChartReportDataPane<DemoDataConfig> {
private TinyFormulaPane xPane;
private TinyFormulaPane yPane;
private TinyFormulaPane zPane;
@Override
protected String[] fieldLabel() {
return new String[]{
"X轴",
"Y轴",
"Z轴"
};
}
@Override
protected TinyFormulaPane[] formulaPanes() {
if (xPane == null) {
xPane = new TinyFormulaPane();
yPane = new TinyFormulaPane();
zPane = new TinyFormulaPane();
}
return new TinyFormulaPane[]{
xPane,
yPane,
zPane
};
}
@Override
protected void populate(DemoDataConfig dataConf) {
populateField(xPane, dataConf.getX());
populateField(yPane, dataConf.getY());
populateField(zPane, dataConf.getZ());
}
@Override
protected DemoDataConfig update() {
DemoDataConfig dataConfig = new DemoDataConfig();
updateField(xPane, dataConfig.getX());
updateField(yPane, dataConfig.getY());
updateField(zPane, dataConfig.getZ());
return dataConfig;
}
}
第五步:
图表插件接口xxx,继承抽象类AbstractExtentChartProvider。
eg:
实现抽象方法:createChart (返回第三步的实例对象xxxChart,后台图表对象)。
package com.fr.plugin.extended.chart.demo;
import com.fr.extended.chart.AbstractChart;
import com.fr.extended.chart.AbstractExtentChartProvider;
/**
* Created by shine on 2018/3/24.
*/
public class Demo extends AbstractExtentChartProvider {
@Override
protected AbstractChart createChart() {
return new DemoChart();
}
}
图表界面插件接口xxxUI,继承AbstractExtendedChartUIProvider。
eg:实现接口方法:getTableDataSourcePane && getReportDataSourcePane (返回第四步定义的两个数据配置界面的实例对象)&&getIconPath(表单工具栏拖拽图表小图标)。
package com.fr.plugin.extended.chart.demo;
import com.fr.design.mainframe.chart.gui.data.report.AbstractReportDataContentPane;
import com.fr.extended.chart.AbstractExtendedChartTableDataPane;
import com.fr.extended.chart.AbstractExtendedChartUIProvider;
/**
* Created by shine on 2018/3/24.
*/
public class DemoUI extends AbstractExtendedChartUIProvider {
@Override
protected AbstractExtendedChartTableDataPane getTableDataSourcePane() {
return new DemoTableDataPane();
}
@Override
protected AbstractReportDataContentPane getReportDataSourcePane() {
return new DemoReportDataPane();
}
@Override
public String getIconPath() {
return "com/fr/plugin/extended/chart/demo/icon.png";
}
}
第六步:插件相关。
新建plugin.xml文件,内容拷贝下面内容,需要更改的字段有:
id:插件id。com.fr.plugin.demoChart 换成自己的,比如com.fr.plugin.xxxChart。
name:插件名称。DEMO图表 换成自己的。
function-recorder: 插件功能点记录。很重要!!!。class写第三步定义的类的路径即可。同时需要给第三步定义的类添加注解@FunctionRecorder,方法addJSON添加注解@ExecuteFunctionRecord
IndependentChartProvider:图表接口。class写第五步中的xxx路径。plotID为 第三步中图表对象实现的抽象方法getChartID返回的结果。
IndependentChartUIProvider:图表UI接口。class写第五步中的xxxUI路径。plotID为 第三步中图表对象实现的抽象方法getChartID返回的结果。
<?xml version="1.0" encoding="UTF-8" standalone="no"?><plugin>
<id>com.fr.plugin.demoChart</id>
<name><![CDATA[DEMO图表]]></name>
<active>yes</active>
<version>1.0.0</version>
<env-version>10.0</env-version>
<jartime>2018-3-31</jartime>
<vendor>finereport.shine</vendor>
<description><![CDATA[给开发者参考的图表插件demo]]></description>
<change-notes><![CDATA[]]></change-notes>
<function-recorder class="com.fr.plugin.demo.DemoChart"/>
<extra-chart>
<IndependentChartProvider class="com.fr.plugin.demo.Demo" plotID="DEMO_CHART"/>
</extra-chart>
<extra-chart-designer>
<IndependentChartUIProvider class="com.fr.plugin.demo.DemoUI" plotID="DEMO_CHART"/>
</extra-chart-designer>
</plugin>
/**
* Created by shine on 2018/3/24.
*/
@FunctionRecorder
public class DemoChart extends AbstractChart<DemoDataConfig>{
@ExecuteFunctionRecord
@Override
protected void addJSON(DemoDataConfig dataConfig, JSONObject jsonObject, Repository repo) throws JSONException {
JSONArray array = JSONFactory.createJSON(JSON.ARRAY);
List<Object> xValues = dataConfig.getX().getValues();
List<Object> yValues = dataConfig.getY().getValues();
List<Object> zValues = dataConfig.getZ().getValues();
......其余省略,主要看@FunctionRecorder && @ExecuteFunctionRecord
简单的开发到此结束,如果想要联动or超链or导出or公式等,请参考开发进阶
4 Comments
Anonymous
dream2874
这个插件如何在系统里跑起来啊?有没有详细的步骤啊?
chenmf
自己技术不行,还不尊重别人的劳动成果,真是毁三观
zheng-郑潇
默认会 check license,前端有提示水印,后台图表对象xxxChart 中加入下面方法就没有水印了
protected void checkLicense(JSONObject jsonObject) throws JSONException {
}