【仅供内部供应商使用,不提供对外解答和培训】

Page tree

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

demo地址:plugin-demochart

 

Table of Contents

...

css文件。

xxxChart重写requiredCSS.

Code Block
collapsetrue
@Override
protected String[] requiredCSS() {
    return new String[] {
            "com/fr/plugin/demo/demo.css"
    };
} 

...

超链。

首先:实现前期准备中第三步中后台图表xxxChart的抽象方法 hyperLinkParas。

Code Block
collapsetrue
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

Code Block
collapsetrue
@Override
public AbstractChartAttrPane[] getAttrPaneArray(AttributeChangeListener listener) {
    return new AbstractChartAttrPane[]{
            new ExtendedOtherPane()
    };
}

最后:在前期准备第二步写的前端图表对象xxxWrapper中的初始方法_init中 绑定事件处理函数getLinkFun。ps:这边是echarts的定义事件接口,不同前端库实现不同。比如fr自带vancharts是option.onClick this.getLinkFun();

Code Block
collapsetrue
_init: function (dom, option) {
    var chart = echarts.init(dom);
    //绑定点击触发超链函数
    chart.on('click', this.getLinkFun());
    chart.setOption(option);
    return chart;
},

...

自动刷新。

首先:在前期准备第二步写的前端图表对象xxxWrapper中添加方法_refresh。方法体 调用所用图表库的刷新图表接口。

Code Block
collapsetrue
_refresh: function (chart, option) {
    chart.setOption(option);
},

其次:和超链中的其次一样。

重写前期准备第五步中 图表界面插件接口xxxUI中的方法getAttrPaneArray

Code Block
collapsetrue
@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。

Code Block
collapsetrue
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。

Code Block
titleDemoTitlePane
collapsetrue
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(返回样式配置面板数组)。

Code Block
titleDemoStylePane
collapsetrue
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

Code Block
collapsetrue
@Override
public AbstractChartAttrPane[] getAttrPaneArray(AttributeChangeListener listener) {
    return new AbstractChartAttrPane[]{
            new DemoStylePane()
    };
}

 

...

联动&公式。

因为上一步骤配置标题的已经写好。要想标题可以使用公式。只需要实现前期准备中第三步中xxxChart的抽象方法 formulas。返回所有需要处理的公式属性集合。

Code Block
collapsetrue
@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()。

Code Block
protected ExportProcessor createExportProcessor() {
 return new JSExportProcessor();
} 

ps:如果返回的是JSExportProcessor,必须:需要在前期准备第二步写的前端图表对象xxxWrapper中添加方法_exportImage,调用所用图表库的导出图片接口;_exportInit,图表初始接口+导出特殊处理,这个可以不加,不加的情况使用_init

Code Block
collapsetrue
_exportInit:function (dom, option) {
    option.animation = false;
    return this._init(dom, option);
},

_exportImage: function (chart) {
    return chart.getConnectedDataURL({type: 'png'})
}

ps:如果选择的是PhantomExportProcessor,可选:这时候如果你希望设计器展示的图表不仅仅是一张固定的图片,设置的样式属性(除了数据配置,我们暂时称其他属性为样式属性)可以随着你的配置实时改变,你可以重写前期准备第三步后台图表对象xxxChart中的designerDataConfig方法(固定数据配置)。

Code Block
collapsetrue
@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)方法。

Code Block
titleDemoTypePane
collapsetrue
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。

Code Block
languagejava
@Override
public AbstractChartTypePane getPlotTypePane() {
    return new DemoTypePane();
}

...

类型界面添加多种详细类型。

首先,定义枚举类型yyyType。

Code Block
titleThemeType
collapsetrue
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中。

Code Block
collapsetrue
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

Code Block
languagejava
collapsetrue
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。重写相关方法。

Code Block
collapsetrue
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中添加组件以及重写一些方法。

Code Block
collapsetrue
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 也无需定义了,可返回任意值。

Code Block
collapsetrue
@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.
Code Block
collapsetrue
    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,按照界面组件顺序返回一个有序的组件数组。(单元格数据源面板同理)。

...

collapsetrue

...

前言:

6个步骤,7个文件,千行代码,so easy !

要开发一款图表,首先要清楚所用前端库的一些基础接口,此图表类型的数据结构。

以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三维柱形图

  1. 第一步:
    定义图表所需数据结构xxxDataConfig,继承抽象类AbstractDataConfig。

    eg :

    声明变量x、y、z(保存配置的xyz轴数据的字段名称)。

    实现抽象方法:readXML(模板读取)&& writeXML(模板写入)&& clone && equals && hashCode && dataSetFields(返回由声明的变量组成的数组,用于预览时取数据库取数)。

    其中,供开发者使用的readExtendedField&writeExtendedField方法的第二个参数是字段写入模板对应的key。

    Code Block
    titleDemoDataConfig
    collapsetrue
    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 new String[]{z;
        }
    
        public void setZ(ExtendedField z)  {
       "X轴",
         this.z = z;
        }
    
        @Override
     "指标名",
       protected void readAttr(XMLableReader reader) {
            readExtendedField(x, "Y轴x", reader);
            readExtendedField(y,    "y", reader);
        "Z轴"
        readExtendedField(z,    }"z", reader);
        }
    
        @Override
        protected Component[]void fieldComponentswriteAttr(XMLPrintWriter writer) {
            if (xComboBox == null) {
    writeExtendedField(x, "x", writer);
            writeExtendedField(y, "y", writer);
         xComboBox = new UIComboBox(writeExtendedField(z, "z", writer);
        }
    
        @Override
        targetNamepublic = new UITextFieldExtendedField[] dataSetFields(); {
            return new ExtendedField[]{
        yComboBox = new UIComboBox();
             x,
       zComboBox = new UIComboBox();
            }
      y,
          return new Component[]{
            z
            xComboBox,};
        }
    
        @Override
        public DemoDataConfig clone() throws CloneNotSupportedException targetName,{
            DemoDataConfig result = new DemoDataConfig();
            yComboBox,result.setX(this.getX().clone());
            result.setY(this.getY().clone());
            zComboBoxresult.setZ(this.getZ().clone());
            }return result;
        }
     
        @Override
       public protected UIComboBox[] filedComboBoxesint hashCode() {
           return if (xComboBox == null) {
                xComboBox = new UIComboBox()super.hashCode() + AssistUtils.hashCode(this.getX(), this.getY(), this.getZ());
       }
    
       @Override
       public boolean equals(Object yComboBox = new UIComboBox();
        obj) {
           return zComboBoxobj = new UIComboBox();instanceof DemoDataConfig
            }
            return new UIComboBox[]{&& AssistUtils.equals(this.getX(), ((DemoDataConfig) obj).getX())
                    xComboBox,
    && AssistUtils.equals(this.getY(), ((DemoDataConfig) obj).getY())
                   && AssistUtils.equals(this.getZ(),  yComboBox,((DemoDataConfig) obj).getZ())
                    zComboBox
         ;
       };
        }
    
    }
  2. 第二步:
    定义前台图表对象xxxWrapper.js,指定图表库的初始图表接口。
    eg:demoWrapper

    Code Block
    titledemoWrapper
    collapsetrue
    demoWrapper = ExtendedChart.extend({
        @Override
        protected void populate(DemoDataConfig dataConf_init:function (dom, option) {
            populateField(xComboBox, dataConf.getX());
            targetName.setText(dataConf.getTargetName()var chart = echarts.init(dom);
            populateField(yComboBox, dataConf.getY()chart.setOption(option);
            populateField(zComboBox, dataConf.getZ())return chart;
        }
    
        @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中。

    Code Block
    collapsetrue
    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
    
    });
  3. 第三步:

    定义后台图表对象xxxChart,继承抽象类AbstractChart。注意点:继承的时候别忘了指定泛型DemoDataConfig,即extends AbstractChart<DemoDataConfig>。

    eg:

    实现抽象方法:getChartID (图表标志ID)&& getChartName(图表名称)  &&  demoImagePath (图表选择界面图片路径) && addJSON (预览时生成的json对象,即图表展现所需配置项option && requiredJS (前端图表库js文件)&& wrapperName(前端图表对象,即第二步定义的对象名称)。

    其中,获取某字段对应的数据库数据使用方法dataConfig.getX().getValues())。

    Code Block
    titleDemoChart
    collapsetrue
    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() {
            jsonObject.put("targetName", dataConfig.getTargetName());
    
    return ID;
        }
    
        @Override
        public forString getChartName(int i = 0, len = xValues.size(); i < len; i++) {) {
            return NAME;
        }
    
        @Override
        maxValueprotected = Math.max(GeneralUtils.objectToNumber(zValues.get(i)).doubleValue(), maxValue);
    String demoImagePath() {
                array.put(JSONFactory.createJSON(JSON.ARRAY).put(xValues.get(i)).put(yValues.get(i)).put(zValues.get(i)))return "com/fr/plugin/extended/chart/demo/demo.png";
        }
    
        }@Override
       protected }
    void addJSON(DemoDataConfig dataConfig, JSONObject jsonObject.put("series", JSONFactory.createJSON(JSON.OBJECT).put("type", "bar3D").put("data", array)
    , Repository repo, JSONPara para) throws JSONException {
    
            JSONArray array = JSONFactory.createJSON(JSON.ARRAY);
    
             .put("bevelSize", 0.2).put("bevelSmoothness", 2).put("shading", "color"));
    
    //省略其它。。。。
    }

    数据集数据源 对一些字段 公式汇总(求和 平均 最大 最小 等)。

    首先,DemoDataConfig中添加两个字段属性expect actual,并添加响应get set 方法,补全read write datasetFields clone hashcode equals方法。

    Code Block
    collapsetrue
      //省略
    List<Object> xValues = dataConfig.getX().getValues();
           private ExtendedFieldList<Object> expectyValues = new ExtendedFielddataConfig.getY().getValues();
         private   ExtendedFieldList<Object> actualzValues = new ExtendedFielddataConfig.getZ().getValues();
    
        public ExtendedField getExpect() {
     double maxValue = Double.MIN_VALUE;
        return expect;
       for }
    
    (int i = 0, publiclen void= setExpect(ExtendedField expect) {
            this.expect = expect;
    xValues.size(); i < len; i++) {
             }
    
       maxValue public ExtendedField getActual() {= Math.max(GeneralUtils.objectToNumber(zValues.get(i)).doubleValue(), maxValue);
    
            return actual;
        }
    
    array.put(JSONFactory.createJSON(JSON.ARRAY).put(xValues.get(i)).put(yValues.get(i)).put(zValues.get(i)));
        public void setActual(ExtendedField actual) {}
            
     this.actual = actual;
        }
    
        @Override jsonObject.put("series", JSONFactory.createJSON(JSON.OBJECT).put("type", "bar3D").put("data", array)
        protected void readAttr(XMLableReader reader) {
            readExtendedField.put(x, "xbevelSize", reader);
            this.setTargetName(reader.getAttrAsString("targetName 0.2).put("bevelSmoothness", 2).put("shading", "color"));
    
            readExtendedField(y, "y", reader);jsonObject.put("xAxis3D", JSONFactory.createJSON(JSON.OBJECT).put("type", "category"))
            readExtendedField(z, "z", reader);
            readExtendedField.put(expect, "expectyAxis3D", reader);
            readExtendedField(actualJSONFactory.createJSON(JSON.OBJECT).put("type", "actualcategory", reader));
        }
    
          @Override
        protected void writeAttr(XMLPrintWriter writer) {
    .put("zAxis3D", JSONFactory.createJSON(JSON.OBJECT).put("type", "value"));
    
             writeExtendedField(x, "x", writer);jsonObject.put("grid3D", JSONFactory.createJSON(JSON.OBJECT).put("boxWidth", 200).put("boxDepth", 80));
    
            writerjsonObject.attrput("targetNamevisualMap", thisJSONFactory.getTargetNamecreateJSON(JSON.OBJECT));
            writeExtendedField(y, "y", writer);
            writeExtendedField.put(z, "zmax", writermaxValue);
            writeExtendedField(expect, "expect", writer);
            writeExtendedField(actual, "actual", writer.put("color", JSONFactory.createJSON(JSON.ARRAY).put("#d94e5d").put("#eac736").put("#50a3ba")));
        }
    
        @Override
        publicprotected ExtendedFieldString[] dataSetFieldsrequiredJS() {
            return new ExtendedFieldString[]{
                    x"com/fr/plugin/extended/chart/demo/demoWrapper.js",
                    y,
                    z,
                    expect"com/fr/plugin/extended/chart/demo/echarts.js",
                    actual"com/fr/plugin/extended/chart/demo/echarts-gl.js"
            };
        }
    
        @Override
        publicprotected DemoDataConfigString clonewrapperName() throws CloneNotSupportedException {
            DemoDataConfig result = new DemoDataConfig();
            result.setX(this.getX().clone());
            result.setTargetName(this.getTargetName())return "demoWrapper";
        }
    
        result.setY(this.getY().clone());@Override
        protected    result.setZ(this.getZ().clone());
    HyperLinkPara[] hyperLinkParas() {
             result.setExpect(this.getExpect().clone());
       return new HyperLinkPara[0];
        }
    
        @Override
         result.setActual(this.getActual().clone());protected List<StringFormula> formulas() {
            return resultnull;
        }
    
        @Override
        publicprotected intExportProcessor hashCodecreateExportProcessor() {
            return null;
        }
    
    }
    
  4. 第四步:数据界面。
    数据集数据界面xxxTableDataPane,继承抽象类AbstractExtendedChartTableDataPane。注意点:extends AbstractExtendedChartTableDataPane<DemoDataConfig>

    eg:

    声明变量下拉框 x、y、z。
    实现抽象方法:fieldLabels  (标签名称)&& filedComboBoxes (下拉框数组)&& populate (属性设置到界面组件)&& update(组件值保存到图表属性中)。

    Code Block
    titleDemoTableDataPane
    collapsetrue
    package   return super.hashCode() + AssistUtils.hashCode(this.getX(), this.getY(), this.getZ(),
                    this.getTargetName(), this.getExpect(), this.getActual());
        }
    
        @Override
        public boolean equals(Object obj) 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    return obj instanceof DemoDataConfigUIComboBox xComboBox;
        private UIComboBox yComboBox;
        private UIComboBox zComboBox;
    
        && AssistUtils.equals(this.getX(), ((DemoDataConfig) obj).getX())@Override
        protected    String[] fieldLabels() {
            && AssistUtils.equals(this.getTargetName(), ((DemoDataConfig) obj).getTargetName())return new String[]{
                    && AssistUtils.equals(this.getY(), ((DemoDataConfig) obj).getY())"X轴",
                    && AssistUtils.equals(this.getZ(), ((DemoDataConfig) obj).getZ())
    "Y轴",
                    "Z轴"
      && AssistUtils.equals(this.getExpect(), ((DemoDataConfig) obj).getExpect())
       };
        }
    
        @Override
        protected && AssistUtils.equals(this.getActual(), ((DemoDataConfig) obj).getActual())
    UIComboBox[] filedComboBoxes() {
            if (xComboBox == null) {
                xComboBox = new UIComboBox();
          ;
        }
    }
    
    

    其次,DemoTableDataPane中声明下拉框组件expect&actual 补全方法labels componnets combobox populate update。

    注意populate对应字段要调用populateFunctionField&update对应字段要调用updateFunctionField。

    Code Block
    collapsetrue
    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; yComboBox = new UIComboBox();
                zComboBox = new UIComboBox();
            }
            return new UIComboBox[]{
                    xComboBox,
                    yComboBox,
                    zComboBox
            };
        }
    
        @Override
        protected String[]void fieldLabelspopulate(DemoDataConfig dataConf) {
            return new String[]{
           populateField(xComboBox, dataConf.getX());
             "X轴",populateField(yComboBox, dataConf.getY());
            populateField(zComboBox, dataConf.getZ());
        }
    
        "指标名",@Override
        protected DemoDataConfig update() {
            DemoDataConfig "Y轴",
    dataConfig = new DemoDataConfig();
    
            updateField(xComboBox, dataConfig.getX());
        "Z轴",
          updateField(yComboBox, dataConfig.getY());
              "预期值",updateField(zComboBox, dataConfig.getZ());
    
            return dataConfig;
        }
    }
    
    

    单元格配置界面xxxReportDataPane,继承抽象类AbstractExtendedChartReportDataPane。处理参考数据集数据配置界面,上栗子,不做累述。

    Code Block
    titleDemoReportDataPane
    collapsetrue
    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() {
        }
    
        @Override
    return new   protected ComponentString[] fieldComponents() {
            if (xComboBox == null) {
         "X轴",
           xComboBox = new UIComboBox();
          "Y轴",
          targetName = new UITextField();
           "Z轴"
         yComboBox = new UIComboBox()};
        }
    
        @Override
        zComboBoxprotected = new UIComboBoxTinyFormulaPane[] formulaPanes(); {
            if    expect (xPane == new UIComboBox();null) {
                expectFunctionxPane = new CalculateComboBoxTinyFormulaPane();
                actualyPane = new UIComboBoxTinyFormulaPane();
                actualFunctionzPane = new CalculateComboBoxTinyFormulaPane();
            }
            return new ComponentTinyFormulaPane[]{
                    xComboBoxxPane,
                    targetNameyPane,
                    yComboBox,zPane
            };
        }
    
        zComboBox,@Override
        protected void populate(DemoDataConfig dataConf) {
            expect,populateField(xPane, dataConf.getX());
            populateField(yPane, dataConf.getY());
            expectFunction,populateField(zPane, dataConf.getZ());
        }
    
        @Override
        protected DemoDataConfig   actual,update() {
            DemoDataConfig dataConfig = new     actualFunction
    DemoDataConfig();
    
             }updateField(xPane, dataConfig.getX());
        }
    
        @OverrideupdateField(yPane, dataConfig.getY());
        protected UIComboBox[] filedComboBoxes() {
        updateField(zPane, dataConfig.getZ());
    
            return ifdataConfig;
     (xComboBox == null) {
                xComboBox = new UIComboBox();
                yComboBox = new UIComboBox();
                zComboBox = new UIComboBox(); }
    }
    
    
  5. 第五步:
    图表插件接口xxx,继承抽象类AbstractExtentChartProvider。
    eg:
    实现抽象方法:createChart (返回第三步的实例对象xxxChart,后台图表对象)

    Code Block
    titleDemo
    collapsetrue
    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();
         expect = new UIComboBox();
                actual = new UIComboBox();
            }
            return new UIComboBox[]{
                    xComboBox,
                    yComboBox,}
    }
    
    

    图表界面插件接口xxxUI,继承AbstractExtendedChartUIProvider。

    eg:实现接口方法:getTableDataSourcePane  && getReportDataSourcePane (返回第四步定义的两个数据配置界面的实例对象)&&getIconPath(表单工具栏拖拽图表小图标)

    Code Block
    titleDemoUI
    collapsetrue
    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();
          zComboBox,}
    
        @Override
        protected AbstractReportDataContentPane       expect,getReportDataSourcePane() {
            return new DemoReportDataPane();
          actual}
    
        @Override
        };
    public String   }
    getIconPath() {
        @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() {return "com/fr/plugin/extended/chart/demo/icon.png";
        }
    }
    
  6. 第六步:插件相关。

    新建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返回的结果。

    Code Block
    titleplugin.xml
    collapsetrue
    <?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>
            DemoDataConfig dataConfig = new DemoDataConfig(); <IndependentChartProvider class="com.fr.plugin.demo.Demo" plotID="DEMO_CHART"/>
        </extra-chart>
    
        <extra-chart-designer>
        updateField(xComboBox, dataConfig.getX());
        <IndependentChartUIProvider class="com.fr.plugin.demo.DemoUI" plotID="DEMO_CHART"/>
        dataConfig.setTargetName(targetName.getText());
            updateField(yComboBox, dataConfig.getY());
            updateField(zComboBox, dataConfig.getZ());
    
            updateFunctionField(expect, expectFunction, dataConfig.getExpect());
    </extra-chart-designer>
    
    </plugin> 
    Code Block
    titlefunction-recorder
    collapsetrue
    /**
     * 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 updateFunctionField(actual, actualFunction, dataConfig.getActual())array = JSONFactory.createJSON(JSON.ARRAY);
    
            returnList<Object> dataConfig;
    xValues    }
    }

    最后,在chart的addjson里面,获取相应字段的values即可。

    数据界面-数据集  字段名(也可自定义字符串)组成一个字段(系列名使用字段名)。

    首先,DemoTableDataPane中复写createExtendedCustomFieldComboBoxPane方法,返回new ExtendedCustomFieldComboBoxPane()。

    Code Block
    collapsetrue
    @Override
    protected ExtendedCustomFieldComboBoxPane createExtendedCustomFieldComboBoxPane() {
    = dataConfig.getX().getValues();
          return new ExtendedCustomFieldComboBoxPane();
    }

    最后,在DemoChart中,直接获取相应的values即可。

    Code Block
    collapsetrue
     List<Object> customNames List<Object> yValues = dataConfig.getCustomNameFieldgetY().getValues();
            List<Object> customValueszValues = dataConfig.getCustomValueFieldgetZ().getValues();
  7. 字段的配置下拉框含有 无 这个选项。

    使用组件 UIComboBoxWithNone即可。

    Code Block
    collapsetrue
    private UIComboBoxWithNone seriesName;
  8. 空数据提示(调用内置图表 空数据提示接口)。

    前期准备第二步写的前端图表对象xxxWrapper中添加方法_emptyData。根据参数options返回是否是空数据。

    Code Block
    _emptyData: function (options) {
        return options.series.data.length === 0;
    }
     
    ......其余省略,主要看@FunctionRecorder && @ExecuteFunctionRecord


    简单的开发到此结束,如果想要联动or超链or导出or公式等,请参考开发进阶