1.4. 连接数据

有两种方法可以向图表传递数据:通过 DataProvider 接口或者使用简化的数据绑定 API。简化的数据绑定 API 可以直接使用 addData() 方法和 MapDataItem 类构造器为没有绑定数据源的图表来添加数据。图表使用示例包含了为图标提供数据的所有方法的介绍。

DataProvider:

DataProvider 接口有两个标准实现: ListDataProvider 类和 ContainerDataProvider 类。

  • ListDataProvider 包含了一个 DataItem 实例的列表,图表的数据将从这个列表里获取。DataItem 接口有一些标准实现:

    • EntityDataItem - 表示任意实体类的实例,从该实例中获取图表数据。

      @Inject
      private PieChart chart;
      
      @Inject
      private Metadata metadata;
      
      @Subscribe
      protected void onInit(InitEvent event) {
          ListDataProvider dataProvider = new ListDataProvider();
          dataProvider.addItem(new EntityDataItem(valueDescription(75, "Sky")));
          dataProvider.addItem(new EntityDataItem(valueDescription(7, "Shady side of pyramid")));
          dataProvider.addItem(new EntityDataItem(valueDescription(18, "Sunny side of pyramid")));
      
          chart.setDataProvider(dataProvider);
      }
      
      private ValueDescription valueDescription(Integer value, String description) {
          ValueDescription entity = metadata.create(ValueDescription.class);
          entity.setValue(value);
          entity.setDescription(description);
          return entity;
      }
    • MapDataItem - 键值对集合,从中获取图表数据。

      @Inject
      private PieChart chart;
      
      @Subscribe
      protected void onInit(InitEvent event) {
          ListDataProvider dataProvider = new ListDataProvider();
          dataProvider.addItem(new MapDataItem(
                  ImmutableMap.of("value", 75, "description", "Sky")));
          dataProvider.addItem(new MapDataItem(
                  ImmutableMap.of("value", 7, "description", "Shady side of pyramid")));
          dataProvider.addItem(new MapDataItem(
                  ImmutableMap.of("value", 18, "description", "Sunny side of pyramid")));
      
          chart.setDataProvider(dataProvider);
      }
    • SimpleDataItem - 表示任意 public 类的实例,从中获取图表数据。

      @Inject
      private PieChart chart;
      
      @Subscribe
      protected void onInit(InitEvent event) {
          ListDataProvider dataProvider = new ListDataProvider();
          dataProvider.addItem(new SimpleDataItem(new ValueDescription(75, "Sky")));
          dataProvider.addItem(new SimpleDataItem(new ValueDescription(7, "Shady side of pyramid")));
          dataProvider.addItem(new SimpleDataItem(new ValueDescription(18, "Sunny side of pyramid")));
      
          chart.setDataProvider(dataProvider);
      }
      
      public class ValueDescription {
          private Integer value;
          private String description;
      
          public ValueDescription(Integer value, String description) {
              this.value = value;
              this.description = description;
          }
      
          public Integer getValue() {
              return value;
          }
      
          public String getDescription() {
              return description;
          }
      }
  • ContainerDataProvider 用于给 Chart 组件分配一个 CollectionContainer

    假设我们有数据容器和数据加载器用来加载 TransportCount 实例。下面是界面 XML 描述的片段:

    <data>
        <collection id="transportCountsDc"
                    class="com.company.sampler.entity.TransportCount"
                    view="_local">
            <loader id="transportCountsDl">
                    <query><![CDATA[select e from sampler_TransportCount e order by e.year]]></query>
            </loader>
        </collection>
    </data>
    <layout>
        <chart:serialChart id="stackedArea"
                           marginLeft="0"
                           marginTop="10"
                           plotAreaBorderAlpha="0"
                           height="100%"
                           width="100%">
            <!--...-->
        </chart:serialChart>
    </layout>

    界面控制器定义了 onInit() 方法,设置了 stackedArea 图表的 data provider。Data provider 是基于 transportCountsDc 数据容器。

    @UiController("sampler_StackedareaChartSample")
    @UiDescriptor("stackedarea-chart-sample.xml")
    @LoadDataBeforeShow
    public class StackedareaChartSample extends Screen {
    
        @Inject
        private CollectionContainer<TransportCount> transportCountsDc;
    
        @Inject
        private SerialChart stackedArea;
    
        @Subscribe
        private void onInit(InitEvent event) {
            stackedArea.setDataProvider(new ContainerDataProvider(transportCountsDc));
            stackedArea.setCategoryField("year");
        }
    }

    这种方式需要一个实体来表示图表数据。如果应用程序数据模型中已经存在这样的一个实体,并且图表数据是要显示为表格时,这种方式可能就比较方便。

DataProvider 的实例被传递给图表(chart configuration)配置的 setDataProvider() 方法。 这种提供图表数据的方法是最通用的,但它需要在界面控制器中创建 DataProviderDataItem 的实例。

DataProvider 实例中包含用来展示的实体属性或者值需要在图表属性中定义。根据图表类型的不同,图表属性集合也不一样。比如,对于 chart:pieChart 组件,需要定义 valueFieldtitleField 属性。属性值可以使用这些类型:IntegerLongDoubleStringBooleanDate

DataProvider 机制支持对已经渲染的图表动态添加数据。

chart:data 元素:

这个元素可以用来快速的做图表原型。使用 chart:data 和内部嵌套的 item 元素可以直接在图表的 XML 描述中设置键值对类型的数据,示例:

<chart:pieChart id="pieChart"
                titleField="key"
                valueField="value">
    <chart:data>
        <chart:item>
            <chart:property name="key" value="piece of apple pie"/>
            <chart:property name="value" value="70" type="int"/>
        </chart:item>
        <chart:item>
            <chart:property name="key" value="piece of blueberry pie"/>
            <chart:property name="value" value="20" type="int"/>
        </chart:item>
        <chart:item>
            <chart:property name="key" value="piece of cherry pie"/>
            <chart:property name="value" value="10" type="int"/>
        </chart:item>
    </chart:data>
</chart:pieChart>