xxxChart重写requiredCSS.
@Override protected String[] requiredCSS() { return new String[] { "com/fr/plugin/demo/demo.css" }; } |
首先:实现前期准备中第三步中后台图表xxxChart的抽象方法 hyperLinkParas。
private static final HyperLinkPara X = new HyperLinkPara() { @Override public String getName() { return "X轴"; } @Override public String getFormulaContent() { return "X"; } @Override public String[] getProps() { return new String[]{"data", "0"}; } }; private static final HyperLinkPara Y = new HyperLinkPara() { @Override public String getName() { return "Y轴"; } @Override public String getFormulaContent() { return "Y"; } @Override public String[] getProps() { return new String[]{"data", "1"}; } }; private static final HyperLinkPara[] PARAS = new HyperLinkPara[]{ X, Y }; protected HyperLinkPara[] hyperLinkParas() { return PARAS; } |
其次:重写前期准备第五步中 图表界面插件接口xxxUI中的方法getAttrPaneArray
@Override public AbstractChartAttrPane[] getAttrPaneArray(AttributeChangeListener listener) { return new AbstractChartAttrPane[]{ new ExtendedOtherPane() }; } |
最后:在前期准备第二步写的前端图表对象xxxWrapper中的初始方法_init中 绑定事件处理函数getLinkFun。ps:这边是echarts的定义事件接口,不同前端库实现不同。比如fr自带vancharts是option.onClick = this.getLinkFun();
_init: function (dom, option) { var chart = echarts.init(dom); //绑定点击触发超链函数 chart.on('click', this.getLinkFun()); chart.setOption(option); return chart; }, |
首先:在前期准备第二步写的前端图表对象xxxWrapper中添加方法_refresh。方法体 调用所用图表库的刷新图表接口。
_refresh: function (chart, option) { chart.setOption(option); }, |
其次:和超链中的其次一样。
重写前期准备第五步中 图表界面插件接口xxxUI中的方法getAttrPaneArray
@Override public AbstractChartAttrPane[] getAttrPaneArray(AttributeChangeListener listener) { return new AbstractChartAttrPane[]{ new ExtendedOtherPane() }; } |
大小颜色标题图例等等。栗子:标题。注意:添加属性需要完善read&&write&clone&equals&populate&update,缺一不可。
首先:在前期准备中第三步中xxxChart中添加属性stringTitle & 重写readAttr和writeAttr方法&clone&equals&addJSON添加到前台option中。如果添加的属性不是基本数据类型,需要重写方法readXML&writeXML。
private StringFormula titleFormula = new StringFormula(); public StringFormula getTitleFormula() { return titleFormula; } public void setTitleFormula(StringFormula titleFormula) { this.titleFormula = titleFormula; } @Override protected void readAttr(XMLableReader reader) { super.readAttr(reader); this.getTitleFormula().readAttr("title", reader); } @Override protected void writeAttr(XMLPrintWriter writer) { super.writeAttr(writer); this.getTitleFormula().writeAttr("title", writer); } @Override public Object clone() throws CloneNotSupportedException { DemoChart result = (DemoChart) super.clone(); if (getTitleFormula() != null) { result.setTitleFormula(this.getTitleFormula().clone()); } return result; } @Override public int hashCode() { return super.hashCode() + AssistUtils.hashCode(this.getTitleFormula()); } @Override public boolean equals(Object ob) { return super.equals(ob) && ob instanceof DemoChart && AssistUtils.equals(this.getTitleFormula(), ((DemoChart) ob).getTitleFormula()) ; } @ExecuteFunctionRecord @Override protected void addJSON(DemoDataConfig dataConfig, JSONObject jsonObject, Repository repo, JSONPara para) throws JSONException { jsonObject.put("title", JSONFactory.createJSON(JSON.OBJECT).put("text", getTitleFormula().getResult())); } |
其次:定义标题面板xxxTitlePane。继承类ExtendedScrollPane。实现方法 populateBean&updateBean&createContentPane&title4PopupWindow。注意:泛型DemoChart。
package com.fr.plugin.demo; import com.fr.design.formula.TinyFormulaPane; import com.fr.extended.chart.ExtendedScrollPane; import javax.swing.JPanel; import java.awt.BorderLayout; /** * Created by shine on 2018/3/25. */ public class DemoTitlePane extends ExtendedScrollPane<DemoChart>{ private TinyFormulaPane title; @Override public void populateBean(DemoChart ob) { title.populateBean(ob.getTitleFormula().getContent()); } @Override public void updateBean(DemoChart ob) { ob.getTitleFormula().setContent(title.updateBean()); } @Override protected JPanel createContentPane() { JPanel panel = new JPanel(new BorderLayout()); title = new TinyFormulaPane(); panel.add(title, BorderLayout.CENTER); return panel; } @Override protected String title4PopupWindow() { return "标题"; } } |
再次:定义样式面板xxxStylePane。实现抽象方法initPaneList(返回样式配置面板数组)。
package com.fr.plugin.demo; import com.fr.extended.chart.AbstractExtendedStylePane; import com.fr.extended.chart.ExtendedScrollPane; import java.util.ArrayList; import java.util.List; /** * Created by shine on 2018/3/25. */ public class DemoStylePane extends AbstractExtendedStylePane<DemoChart>{ @Override protected List<ExtendedScrollPane<DemoChart>> initPaneList() { List<ExtendedScrollPane<DemoChart>> list = new ArrayList<ExtendedScrollPane<DemoChart>>(); list.add(new DemoTitlePane()); return list; } } |
最后:重写前期准备第五步中 图表界面插件接口xxxUI中的方法getAttrPaneArray
@Override public AbstractChartAttrPane[] getAttrPaneArray(AttributeChangeListener listener) { return new AbstractChartAttrPane[]{ new DemoStylePane() }; } |
因为上一步骤配置标题的已经写好。要想标题可以使用公式。只需要实现前期准备中第三步中xxxChart的抽象方法 formulas。返回所有需要处理的公式属性集合。
@Override protected List<StringFormula> formulas() { List<StringFormula> list = new ArrayList<StringFormula>(); list.add(this.getTitleFormula()); return list; } |
实现前期准备中第三步中xxxChart的抽象方法 createExportProcessor
说明:
使用webgl flash等phantomjs不支持的前端库,只能使用web端导出用前端图表库导出接口。返回new JSExportProcessor()。
非webgl等,即可使用phantomjs导出,也可使用前端库的导出接口。返回new PhantomExportProcessor() 或者 new JSExportProcessor()。
protected ExportProcessor createExportProcessor() { return new JSExportProcessor(); } |
ps:如果返回的是JSExportProcessor,必须:需要在前期准备第二步写的前端图表对象xxxWrapper中添加方法_exportImage,调用所用图表库的导出图片接口;_exportInit,图表初始接口+导出特殊处理,这个可以不加,不加的情况使用_init
_exportInit:function (dom, option) { option.animation = false; return this._init(dom, option); }, _exportImage: function (chart) { return chart.getConnectedDataURL({type: 'png'}) } |
ps:如果选择的是PhantomExportProcessor,可选:这时候如果你希望设计器展示的图表不仅仅是一张固定的图片,设置的样式属性(除了数据配置,我们暂时称其他属性为样式属性)可以随着你的配置实时改变,你可以重写前期准备第三步后台图表对象xxxChart中的designerDataConfig方法(固定数据配置)。
@Override protected DemoDataConfig designerDataConfig() { DemoDataConfig demoDataConfig = new DemoDataConfig(); demoDataConfig.setX(new ExtendedField("days", new String[]{"Monday","Tuesday"})); demoDataConfig.setY(new ExtendedField("name", new String[]{"Lily", "Marks"})); demoDataConfig.setZ(new ExtendedField("money", new String[]{"100", "200"})); return super.designerDataConfig(); } |
首先,定义xxxTypePane,继承ExtendedTypePane。重写 getTypeIconPath(图标路径)&& getTypeTipName(tooltip)方法。
package com.fr.plugin.demo; import com.fr.extended.chart.ExtendedTypePane; /** * Created by shine on 2018/4/19. */ public class DemoTypePane extends ExtendedTypePane { @Override protected String[] getTypeIconPath() { return new String[]{ "com/fr/plugin/demo/icon.png" }; } @Override protected String[] getTypeTipName() { return new String[]{ "demo tooltip" }; } } |
其次,重写前期准备第五步中 图表界面插件接口xxxUI中的方法getPlotTypePane.返回上面的xxxTypePane。
@Override public AbstractChartTypePane getPlotTypePane() { return new DemoTypePane(); } |
首先,定义枚举类型yyyType。
package com.fr.plugin.demo; /** * Created by shine on 2018/4/19. */ public enum ThemeType { DARK, WHITE; public static ThemeType parseInt(int index) { for (ThemeType type : ThemeType.values()) { if (type.ordinal() == index) { return type; } } return DARK; } } |
其次,类似此页面中的3更多样式配置中属性的添加,在前期准备中第三步中xxxChart中添加属性themeType & 重写readAttr和writeAttr方法&clone&equals&addJSON添加到前台option中。
private ThemeType themeType = ThemeType.DARK; public ThemeType getThemeType() { return themeType; } public void setThemeType(ThemeType themeType) { this.themeType = themeType; } @Override protected void readAttr(XMLableReader reader) { super.readAttr(reader); this.setThemeType(ThemeType.parseInt(reader.getAttrAsInt("theme", 0))); this.getTitleFormula().readAttr("title", reader); } @Override protected void writeAttr(XMLPrintWriter writer) { super.writeAttr(writer); writer.attr("theme", getThemeType().ordinal()); this.getTitleFormula().writeAttr("title", writer); } @Override public Object clone() throws CloneNotSupportedException { DemoChart result = (DemoChart) super.clone(); if (getTitleFormula() != null) { result.setTitleFormula(this.getTitleFormula().clone()); } result.setThemeType(this.getThemeType()); return result; } @Override public int hashCode() { return super.hashCode() + AssistUtils.hashCode(this.getTitleFormula(), this.getThemeType()); } @Override public boolean equals(Object ob) { return super.equals(ob) && ob instanceof DemoChart && AssistUtils.equals(this.getTitleFormula(), ((DemoChart) ob).getTitleFormula()) && AssistUtils.equals(this.getThemeType(), ((DemoChart) ob).getThemeType()) ; } @ExecuteFunctionRecord @Override protected void addJSON(DemoDataConfig dataConfig, JSONObject jsonObject, Repository repo) throws JSONException { jsonObject.put("theme", getThemeType() == ThemeType.DARK ? "dark" : "sth whatever"); jsonObject.put("title", JSONFactory.createJSON(JSON.OBJECT).put("text", getTitleFormula().getResult())); ... 省略其它 |
最后,重写上一步骤xxxTypePane中的getTypeIndex && setType(界面到图表对象的一个存取映射)。注意:泛型DemoChart
package com.fr.plugin.demo; import com.fr.extended.chart.ExtendedTypePane; /** * Created by shine on 2018/4/19. */ public class DemoTypePane extends ExtendedTypePane<DemoChart>{ @Override protected String[] getTypeIconPath() { return new String[]{ "com/fr/plugin/demo/dark.png", "com/fr/plugin/demo/white.png" }; } @Override protected String[] getTypeTipName() { return new String[]{ "深色主题", "浅色主题" }; } @Override protected int getTypeIndex(DemoChart chart) { return chart.getThemeType().ordinal(); } @Override protected void setType(DemoChart chart, int index) { chart.setThemeType(ThemeType.parseInt(index)); } } |
首先,在xxxChart里面添加属性 threeDimensional。重写相关方法。
private boolean threeDimensional = false; public boolean isThreeDimensional() { return threeDimensional; } public void setThreeDimensional(boolean threeDimensional) { this.threeDimensional = threeDimensional; } @Override protected void readAttr(XMLableReader reader) { super.readAttr(reader); this.setThemeType(ThemeType.parseInt(reader.getAttrAsInt("theme", 0))); this.setThreeDimensional(reader.getAttrAsBoolean("threeD", false)) } @Override protected void writeAttr(XMLPrintWriter writer) { super.writeAttr(writer); writer.attr("theme", getThemeType().ordinal()); writer.attr("threeD", isThreeDimensional()); } @Override public Object clone() throws CloneNotSupportedException { DemoChart result = (DemoChart) super.clone(); result.setThemeType(this.getThemeType()); result.setThreeDimensional(this.isThreeDimensional()); return result; } @Override public int hashCode() { return super.hashCode() + AssistUtils.hashCode(this.getTitleFormula(), this.getThemeType(), this.isThreeDimensional()); } @Override public boolean equals(Object ob) { return super.equals(ob) && ob instanceof DemoChart && AssistUtils.equals(this.getThemeType(), ((DemoChart) ob).getThemeType()) && AssistUtils.equals(this.isThreeDimensional(), ((DemoChart) ob).isThreeDimensional()) ; } |
其次,xxxTypePane中添加组件以及重写一些方法。
private UIButtonGroup buttonGroup; @Override protected Component[][] getPaneComponents(JPanel typePane) { buttonGroup = new UIButtonGroup(new String[]{"3d", "2d"}); return new Component[][]{ new Component[]{typePane}, new Component[]{buttonGroup} }; } @Override protected void populate(DemoChart chart) { super.populate(chart); buttonGroup.setSelectedIndex(chart.isThreeDimensional() ? 0 : 1); } @Override protected void update(DemoChart chart) { super.update(chart); chart.setThreeDimensional(buttonGroup.getSelectedIndex() == 0); } |
DemoUI中getChartDataPane 返回null即可。当然,getTableDataSourcePane && getReportDataSourcePane 也无需定义了,可返回任意值。
@Override protected AbstractExtendedChartTableDataPane getTableDataSourcePane() { return null; } @Override protected AbstractReportDataContentPane getReportDataSourcePane() { return null; } @Override public ChartDataPane getChartDataPane(AttributeChangeListener listener) { return null; } |
首先,DemoDataConfig中添加自定义属性targetName,补充相应方法set&get&read&write&clone&hashcode&equals.
private ExtendedField x = new ExtendedField(); private String targetName; private ExtendedField y = new ExtendedField(); private ExtendedField z = new ExtendedField(); //省略其它。。。 public String getTargetName() { return targetName; } public void setTargetName(String targetName) { this.targetName = targetName; } @Override protected void readAttr(XMLableReader reader) { readExtendedField(x, "x", reader); this.setTargetName(reader.getAttrAsString("targetName", "")); readExtendedField(y, "y", reader); readExtendedField(z, "z", reader); } @Override protected void writeAttr(XMLPrintWriter writer) { writeExtendedField(x, "x", writer); writer.attr("targetName", this.getTargetName()); 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.setTargetName(this.getTargetName()); 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(), this.getTargetName()); } @Override public boolean equals(Object obj) { return obj instanceof DemoDataConfig && AssistUtils.equals(this.getX(), ((DemoDataConfig) obj).getX()) && AssistUtils.equals(this.getTargetName(), ((DemoDataConfig) obj).getTargetName()) && AssistUtils.equals(this.getY(), ((DemoDataConfig) obj).getY()) && AssistUtils.equals(this.getZ(), ((DemoDataConfig) obj).getZ()) ; } |
其次,数据集数据源面板DemoTableDataPane中添加 private UITextField targetName; 补充相关方法fieldLabels&populate&update。重点:重写方法fieldComponents,按照界面组件顺序返回一个有序的组件数组。(单元格数据源面板同理)。
private UIComboBox xComboBox; private UITextField targetName; private UIComboBox yComboBox; private UIComboBox zComboBox; @Override protected String[] fieldLabels() { return new String[]{ "X轴", "指标名", "Y轴", "Z轴" }; } @Override protected Component[] fieldComponents() { if (xComboBox == null) { xComboBox = new UIComboBox(); targetName = new UITextField(); yComboBox = new UIComboBox(); zComboBox = new UIComboBox(); } return new Component[]{ xComboBox, targetName, yComboBox, zComboBox }; } @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()); targetName.setText(dataConf.getTargetName()); populateField(yComboBox, dataConf.getY()); populateField(zComboBox, dataConf.getZ()); } @Override protected DemoDataConfig update() { DemoDataConfig dataConfig = new DemoDataConfig(); updateField(xComboBox, dataConfig.getX()); dataConfig.setTargetName(targetName.getText()); updateField(yComboBox, dataConfig.getY()); updateField(zComboBox, dataConfig.getZ()); return dataConfig; } } |
最后,DemoChart的addJSON中将此属性根据前台接口加到json中。
protected void addJSON(DemoDataConfig dataConfig, JSONObject jsonObject, Repository repo) throws JSONException { //省略其它。。。。 JSONArray array = JSONFactory.createJSON(JSON.ARRAY); double maxValue = Double.MIN_VALUE; if (dataConfig != null) { List<Object> xValues = dataConfig.getX().getValues(); List<Object> yValues = dataConfig.getY().getValues(); List<Object> zValues = dataConfig.getZ().getValues(); //here jsonObject.put("targetName", dataConfig.getTargetName()); 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")); //省略其它。。。。 } |
首先,DemoDataConfig中添加两个字段属性expect actual,并添加响应get set 方法,补全read write datasetFields clone hashcode equals方法。
//省略 private ExtendedField expect = new ExtendedField(); private ExtendedField actual = new ExtendedField(); public ExtendedField getExpect() { return expect; } public void setExpect(ExtendedField expect) { this.expect = expect; } public ExtendedField getActual() { return actual; } public void setActual(ExtendedField actual) { this.actual = actual; } @Override protected void readAttr(XMLableReader reader) { readExtendedField(x, "x", reader); this.setTargetName(reader.getAttrAsString("targetName", "")); readExtendedField(y, "y", reader); readExtendedField(z, "z", reader); readExtendedField(expect, "expect", reader); readExtendedField(actual, "actual", reader); } @Override protected void writeAttr(XMLPrintWriter writer) { writeExtendedField(x, "x", writer); writer.attr("targetName", this.getTargetName()); writeExtendedField(y, "y", writer); writeExtendedField(z, "z", writer); writeExtendedField(expect, "expect", writer); writeExtendedField(actual, "actual", writer); } @Override public ExtendedField[] dataSetFields() { return new ExtendedField[]{ x, y, z, expect, actual }; } @Override public DemoDataConfig clone() throws CloneNotSupportedException { DemoDataConfig result = new DemoDataConfig(); result.setX(this.getX().clone()); result.setTargetName(this.getTargetName()); result.setY(this.getY().clone()); result.setZ(this.getZ().clone()); result.setExpect(this.getExpect().clone()); result.setActual(this.getActual().clone()); return result; } @Override public int hashCode() { return super.hashCode() + AssistUtils.hashCode(this.getX(), this.getY(), this.getZ(), this.getTargetName(), this.getExpect(), this.getActual()); } @Override public boolean equals(Object obj) { return obj instanceof DemoDataConfig && AssistUtils.equals(this.getX(), ((DemoDataConfig) obj).getX()) && AssistUtils.equals(this.getTargetName(), ((DemoDataConfig) obj).getTargetName()) && AssistUtils.equals(this.getY(), ((DemoDataConfig) obj).getY()) && AssistUtils.equals(this.getZ(), ((DemoDataConfig) obj).getZ()) && AssistUtils.equals(this.getExpect(), ((DemoDataConfig) obj).getExpect()) && AssistUtils.equals(this.getActual(), ((DemoDataConfig) obj).getActual()) ; } } |
其次,DemoTableDataPane中声明下拉框组件expect&actual 补全方法labels componnets combobox populate update。
注意populate对应字段要调用populateFunctionField&update对应字段要调用updateFunctionField。
package com.fr.plugin.demo; import com.fr.design.gui.icombobox.UIComboBox; import com.fr.design.gui.itextfield.UITextField; import com.fr.design.mainframe.chart.gui.data.CalculateComboBox; import com.fr.extended.chart.AbstractExtendedChartTableDataPane; import java.awt.Component; /** * Created by shine on 2018/3/24. */ public class DemoTableDataPane extends AbstractExtendedChartTableDataPane<DemoDataConfig>{ private UIComboBox xComboBox; private UITextField targetName; private UIComboBox yComboBox; private UIComboBox zComboBox; private UIComboBox expect; private CalculateComboBox expectFunction; private UIComboBox actual; private CalculateComboBox actualFunction; @Override protected String[] fieldLabels() { return new String[]{ "X轴", "指标名", "Y轴", "Z轴", "预期值", "预期汇总方式", "实际值", "实际汇总方式" }; } @Override protected Component[] fieldComponents() { if (xComboBox == null) { xComboBox = new UIComboBox(); targetName = new UITextField(); yComboBox = new UIComboBox(); zComboBox = new UIComboBox(); expect = new UIComboBox(); expectFunction = new CalculateComboBox(); actual = new UIComboBox(); actualFunction = new CalculateComboBox(); } return new Component[]{ xComboBox, targetName, yComboBox, zComboBox, expect, expectFunction, actual, actualFunction }; } @Override protected UIComboBox[] filedComboBoxes() { if (xComboBox == null) { xComboBox = new UIComboBox(); yComboBox = new UIComboBox(); zComboBox = new UIComboBox(); expect = new UIComboBox(); actual = new UIComboBox(); } return new UIComboBox[]{ xComboBox, yComboBox, zComboBox, expect, actual }; } @Override protected void populate(DemoDataConfig dataConf) { populateField(xComboBox, dataConf.getX()); targetName.setText(dataConf.getTargetName()); populateField(yComboBox, dataConf.getY()); populateField(zComboBox, dataConf.getZ()); populateFunctionField(expect, expectFunction, dataConf.getExpect()); populateFunctionField(actual, actualFunction, dataConf.getActual()); } @Override protected DemoDataConfig update() { DemoDataConfig dataConfig = new DemoDataConfig(); updateField(xComboBox, dataConfig.getX()); dataConfig.setTargetName(targetName.getText()); updateField(yComboBox, dataConfig.getY()); updateField(zComboBox, dataConfig.getZ()); updateFunctionField(expect, expectFunction, dataConfig.getExpect()); updateFunctionField(actual, actualFunction, dataConfig.getActual()); return dataConfig; } } |
最后,在chart的addjson里面,获取相应字段的values即可。
首先,DemoTableDataPane中复写createExtendedCustomFieldComboBoxPane方法,返回new ExtendedCustomFieldComboBoxPane()。
@Override protected ExtendedCustomFieldComboBoxPane createExtendedCustomFieldComboBoxPane() { return new ExtendedCustomFieldComboBoxPane(); } |
最后,在DemoChart中,直接获取相应的values即可。
List<Object> customNames = dataConfig.getCustomNameField().getValues(); List<Object> customValues = dataConfig.getCustomValueField().getValues(); |
使用组件 UIComboBoxWithNone即可。
private UIComboBoxWithNone seriesName; |
在前期准备第二步写的前端图表对象xxxWrapper中添加方法_emptyData。根据参数options返回是否是空数据。
_emptyData: function (options) { return options.series.data.length === 0; } |