序言
本文档介绍了 CUBA 框架的两个功能模块,图表展示和地图展示。这两个子系统在同一个扩展中实现 - charts, 因而在一个项目中只能一起引入。
图表和地图的展示功能目前只能在 web 客户端使用。
目标读者
本手册适用于使用 CUBA 框架构建应用程序的开发人员。此处假设读者熟悉 开发者手册 。
其它材料
本指南以及 CUBA 框架的任何其它文档可从 https://www.cuba-platform.com/documentation 获取。
CUBA 图表展示子系统是基于 AmCharts 库实现的,所以熟悉这个库对图表开发很有帮助。参阅 http://www.amcharts.com 。
反馈
如果您有任何改进本手册的建议,请随时在 GitHub 上报告问题。如果你看到拼写或措辞错误、bug 或不一致的地方,可以直接 fork repo 进行修复。谢谢!
1. 图表展示
CUBA 框架的图表展示扩展支持多样化的图表类型:饼图,折线图,气泡图,雷达图,漏斗图,股票图等等。图表也支持导出。大部分的图表都支持缩放和滚轮操作。图表 只支持 web 客户端。
图表扩展是基于 AmCharts 类库开发的,并且在一定的许可下进行发布使用,如果保留到 AmCharts 网站的链接的话,许可范围内可以免费使用。或者,可以为项目 购买 AmCharts 的许可,这样可以移除链接。
1.1. 添加图表依赖
要在项目中使用图表,在 CUBA Studio 中打开 Project properties 编辑器:点击 CUBA → Project Properties 主菜单项,在 App components 列表中,选中 charts 应用程序组件。Studio 提示重建 Gradle 脚本时,点击确定。
1.2. 配置图表
图表通过 Chart
组件进行展示,该组件可以作为全局的画布(canvas)。图表类型通过子类型接口定义,该接口继承了 Chart
接口。
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...>
不同图表类型对应的 XML 元素:
-
chart:xyChart
– XYChart – 散点图 -
chart:serialChart
– SerialChart – 序列图 -
chart:pieChart
– PieChart – 饼图 -
chart:funnelChart
– FunnelChart – 漏斗图 -
chart:gaugeChart
– AngularGaugeChart – 仪表盘图 -
chart:radarChart
– RadarChart – 雷达图 -
chart:ganttChart
– GanttChart – 甘特图 -
chart:stockChart
– StockChart – 股票图
每种图表类型有其本身的属性和方法,这些属性和方法是从 AmCharts 库的相应图表拷贝过来的。图表的属性和方法的文档可以参阅: http://docs.amcharts.com/3/javascriptcharts 。
下列元素可以用来为所有类型的图表做声明式的配置:
-
chart:allLabels
– 包含label
元素,带有标签文字和其它属性。标签可以放在图表的特定位置,比如:Figure 1. chart:allLabels<chart:allLabels> <chart:label x="200" y="700" text="You can place a label at any position on the chart" color="DARKBLUE" align="CENTER" rotation="-30"/> </chart:allLabels>
-
chart:balloon
– 配置鼠标悬浮在图表上时显示的气球(提示窗)的样式,示例:Figure 2. chart:balloon<chart:graphs> <chart:graph balloonText="[[category]]: [[value]] m/s" bullet="ROUND" fillAlphas="0.3" valueField="value"/> </chart:graphs> <chart:balloon adjustBorderColor="false" color="WHITE" horizontalPadding="10" verticalPadding="8"/>
气球的文字通过每个图表的
balloonText
属性来定义。-
additionalFields
属性可以在图表的所有字段中插入图表的数据值,比如
titleField
,valueField
,category
,value
,description
,percents
,open
等等,另外,HTML 中也能使用。也可以使用
additionalFields
属性从数据提供方获取更多的实体属性。通过这个属性可以将实体属性传递到图表的查询语句中,之后将数据返回给 UI。因此可以在图表的配置中直接使用实体属性的名称。在下面的例子中,
title
是图表的标题,category
是 category 轴的值,value
是 value 轴的值,optional
是IncomeExpenses
实体属性,取出来用来插入到balloonText
中:<chart:serialChart additionalFields="optional" addClassNames="true" categoryField="year" dataContainer="incomeExpensesDc" startDuration="1"> <chart:graphs> <chart:graph alphaField="alpha" balloonText="<span style='font-size:12px;'>[[title]] in [[category]]:<br> <span style='font-size:20px;'>[[value]]</span> [[optional]]</span>" dashLengthField="dashLengthColumn" title="Income" type="COLUMN" valueField="income"/> <...> </chart:graphs> </chart:serialChart>
Figure 3. additionalFields字段列表可以通过英文逗号分隔的字符串声明式添加:
additionalFields="income,expense,vat"
或者通过编程的方式,在界面控制器中添加:
List<String> fields = Arrays.asList("income", "expense", "vat"); ganttChart.setAdditionalFields(fields);
-
-
chart:chartScrollbar
(对于 序列图 和 散点图 有效) – 图表的滚动条。-
可以设置具体图表通过滚动条进行缩放,示例:
Figure 4. chart:chartScrollbar<chart:chartScrollbar graph="g1" autoGridCount="true" scrollbarHeight="30"/>
-
通过
chart:chartScrollbarSettings
元素可以对滚动条的属性进行定制化设置。<chart:chartScrollbarSettings graph="stockGraph" usePeriod="10mm" position="TOP"/>
-
另外,甘特图 可以有一个
chart:valueScrollbar
元素用来做 value 轴的滚动,chart:chartScrollbar
用来做 category 轴的缩放。Figure 5. chart:valueScrollbar<chart:valueScrollbar autoGridCount="true" color="BLACK"/> <chart:chartScrollbar autoGridCount="true" color="DARKOLIVEGREEN"/>
-
-
chart:cursor
– 可选元素,能在图标上添加光标;光标跟着鼠标指针走,展示图表上对应点的数值小弹窗。Figure 6. chart:cursor<chart:chartCursor cursorAlpha="1" cursorColor="#258cbb" cursorPosition="MOUSE" limitToGraph="g1" pan="true" valueLineAlpha="0.2" valueLineBalloonEnabled="true" valueLineEnabled="true" valueZoomable="true"/>
-
chart:data
– 可选元素,用来做数据绑定。一般在做原型的时候使用。 -
chart:export
– 可选元素,可以启用图表导出。默认的导出实现会在图表上添加一个浮动的 download 按钮:Figure 7. chart:export
-
chart:guides
– 水平/垂直参考线。Figure 8. chart:guides<chart:guides> <chart:guide category="2001" dashLength="2" fillAlpha="0.2" fillColor="#CC0000" inside="true" label="fines for speeding increased" labelRotation="90" toCategory="2003"/> <chart:guide category="2007" dashLength="2" inside="true" label="motorcycle fee introduced" labelRotation="90" lineAlpha="1" lineColor="#CC0000"/> </chart:guides>
-
chart:legend
– 定义图表图例的元素,示例:Figure 9. chart:legend<chart:legend autoMargins="false" marginRight="20" markerType="CIRCLE" position="RIGHT" valueText="[[category]]: [[value]] %"/>
-
chart:nativeJson
– 图表的 JSON 配置。
-
chart:titles
– 图表标题,示例:Figure 10. chart:titles<chart:titles> <chart:title alpha="1" bold="true" color="DARKSLATEGREY" size="20" tabIndex="0" text="Main title"/> <chart:title alpha="0.5" color="BISQUE" size="12" text="Subtitle"/> </chart:titles>
-
chart:responsive
– 图表的响应式插件。此插件可以自动调整图表的大小以适应不同的屏幕分辨率。关于
responsive
插件的更多信息可以参阅 AmCharts website。responsive
元素需要包含嵌套的rules
元素,这里可以定义适配的规则。可以设置图表是否显示图例、轴标题、参考线、图表标题、缩放控制器,或者将标签移入图表区域等:<chart:responsive enabled="true"> <chart:rules> <chart:rule maxWidth="400"> <![CDATA[ { "precision": 2, "legend": { "enabled": false }, "valueAxes": { "inside": true } } ]]> </chart:rule> </chart:rules> </chart:responsive>
任何配置属性都可以设置为 null
;此时,系统会使用默认值(除了 AmCharts 文档中提到的特殊情况)。
在界面控制器配置图表也是按照相同的逻辑。可以配置单一属性,也可以配置组合对象:
pieChart.setWidth("700px");
pieChart.setTitleField("description")
.setValueField("value")
.setStartAngle(312)
.setLegend(new Legend()
.setMarkerType(MarkerType.CIRCLE)
.setPosition(LegendPosition.RIGHT)
.setMarginRight(80))
.addLabels(
new Label()
.setText("Sample Chart")
.setSize(26)
.setBold(true)
.setAlign(Align.CENTER),
new Label()
.setText("extra information")
.setAlign(Align.RIGHT))
.setLabelTickColor(Color.GOLDENROD)
.setColors(Arrays.asList(
Color.valueOf("#446493"),
Color.valueOf("#5E3D2C"),
Color.valueOf("#D0A557")))
.setDataProvider(dataProvider);
展示图表使用的信息可以使用 web 模块的主语言消息包进行覆盖或者本地化。在 CUBA GitHub 已经有一些本地化语言包。
1.3. 图表导出
运行程序的所有图表都可以作为图片或者原始数据导出。使用 chart:export
元素来创建默认的导出菜单,默认的菜单有如下选项:
-
Download as… 支持的格式: PNG, JPG, SVG, PDF
-
Save as… 支持的格式: CSV, XLSX, JSON
-
Annotate… 用来在图表中添加个人注解或矢量图形。细节可以参阅:https://www.amcharts.com/export-now-supports-annotating-charts-with-text-icons-arrows/[注解插件]。
-
Print 打开标准打印设置窗口。
导出菜单可以定制化,以便限制用户对图表数据的访问,示例:
<chart:export fileName="my-chart" position="TOP_RIGHT">
<chart:menu>
<chart:item label="PNG" title="Save as PNG" format="PNG"/>
<chart:item label="JPG" title="Save as JPG" format="JPG"/>
</chart:menu>
</chart:export>
这样的话,只显示选择的文件类型相应的下载按钮:
可以定义如下导出设置:
-
backgroundColor
– 导出图片背景色的颜色代码,默认值是#FFFFFF
。 -
dataDateFormat
– 将日期字符串转换成日期对象的格式(只在导出数据时有效)。 -
dateFormat
– 按照给定的格式对 category 轴的时间数据做格式化(只在导出数据时有效)。 -
enabled
– 启用或禁用导出功能。 -
exportSelection
– 只导出选中的数据。默认值是false
。 -
exportTitles
– 将数据字段的名称换成定义的标题。默认值是false
。 -
fileListener
– 如果设置成true
,则会监听拖拽功能,将投入的图片加载作为注解。默认值是false
。 -
fileName
– 生成文件的文件名(根据导出格式的不同会添加相应的文件后缀)。 -
keyListener
– 如果设置成true
,观察按下的键来撤销/恢复对注解的编辑。 -
position
– 导出图标的位置。可能值:TOP_LEFT
,TOP_RIGHT
(默认),BOTTOM_LEFT
,BOTTOM_RIGHT
。 -
removeImages
– 如果设置成true
,导出时会检查并且删除区域从不同领域加载的不必要的图片。
下列属性可以用来定制化每个导出选项:
- JPG
-
-
quality
– 导出图片的质量。可能值:0
–1
。默认值是1
。
-
- PNG, JPG, SVG, PDF
-
-
multiplier
– 生成图片的缩放比例
-
- CSV
-
-
quotes
– 设置是否需要在字符串两端加上双引号。默认值是true
. -
delimiter
– 列分隔符,默认值是 "," (逗号). -
escape
– 定义是否需要转译字符串。默认值是 true. -
withHeader
– 是否带用列名称的表头。默认值是true
.
-
- XLSX
-
-
dateFormat
– XLSX 日期格式,别忘了在 CategoryAxis 里面设置parseDates
为true
。 -
stringify
– 将所有单元格的内容转化成字符串。默认值是false
。 -
withHeader
– 是否带用列名称的表头。默认值是true
。
-
-
-
pageOrientation
– 页面方向。默认值是PORTRAIT
。 -
pageOrigin
– 显示/隐藏生成的 PDF 的来源。默认值是true
。 -
pageSize
– PDF 列表的格式。默认值是A4
。
此外,可以在主消息包中覆盖
label.saved.from
消息的字符串。 -
-
-
delay
– 触发打印之前的延时,单位是秒。 -
lossless
– 启用/禁用打印时图像优化。默认值是false
。
-
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()
方法。 这种提供图表数据的方法是最通用的,但它需要在界面控制器中创建DataProvider
或DataItem
的实例。在
DataProvider
实例中包含用来展示的实体属性或者值需要在图表属性中定义。根据图表类型的不同,图表属性集合也不一样。比如,对于chart:pieChart
组件,需要定义valueField
和titleField
属性。属性值可以使用这些类型:Integer
、Long
、Double
、String
、Boolean
、Date
。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>
1.5. 事件
可以为每种图表的不同类型的事件配置处理函数。以下监听器类型对于所有图表子类型都适用:
-
LegendItemHideListener
– 隐藏一个图例。 -
LegendItemShowListener
– 显示一个图例。 -
LegendLabelClickListener
– 点击图例标签。 -
LegendMarkerClickListener
– 点击图例标记。
其它针对具体图表类型的事件监听器可以在手册的这部分找到。
对事件处理的例子可以参阅 使用事件。
除了监听器之外,SeriesBasedChart
接口包含 zoomOut
、zoomToIndexes
和 zoomToDates
方法用来操纵图表的轴。
类似的 ,CoordinateChart
接口也提供这些方法用来操纵值坐标轴: zoomOutValueAxes
、 zoomOutValueAxis
、 zoomOutValueAxis
、 zoomValueAxisToValues
和 zoomValueAxisToValues
。
1.6. 图表类型
CUBA 框架支持以下这些不同类型的图表。
以下图表组件实现了图表接口:
所有组件都有 NAME
常量,所以可以使用 UiComponents
来创建。
1.6.1. 仪表盘图
使用 AngularGaugeChart
组件可以创建仪表盘图。
该组件的 XML 名称:chart:gaugeChart
-
chart:gaugeChart
的元素 -
-
arrows
– 包含嵌套的arrow
元素,作为图表的箭头。<chart:arrows> <chart:arrow value="60"/> </chart:arrows>
-
axes
– 包含嵌套的axis
元素,作为仪表盘的坐标轴。<chart:axes> <chart:axis id="blue" axisColor="#67b7dc" axisThickness="3" gridInside="false" inside="false" radius="100%" valueInterval="20" tickColor="#67b7dc"/> <chart:axis labelsEnabled="true" axisColor="#fdd400" axisThickness="3" endValue="160" radius="80%" valueInterval="20" tickColor="#fdd400"/> </chart:axes>
使用
band
元素可以将坐标轴分成不同的部分,如上面的图所示:<chart:axes> <chart:axis axisAlpha="0.2" axisThickness="1" bottomText="60 km/h" bottomTextYOffset="-20" endValue="220" tickAlpha="0.2" valueInterval="20"> <chart:bands> <chart:band color="#84b761" endValue="90" startValue="0"/> <chart:band color="#fdd400" endValue="130" startValue="90"/> <chart:band color="#cc4748" endValue="220" innerRadius="95%" startValue="130"/> </chart:bands> </chart:axis> </chart:axes>
endValue
和startValue
属性用来设置图表的值域范围,valueInterval
属性用来显示仪表盘标尺刻度。
-
-
AngularGaugeChart
事件监听器: -
-
ChartClickListener
– 点击画布。 -
ChartRightClickListener
– 右键点击画布。
-
更多细节,参阅 AmCharts 文档。
1.6.2. 漏斗图
使用 FunnelChart
组件可以创建漏斗/金字塔图。
该组件的 XML 名称:chart:funnelChart
- 数据绑定:
-
-
可以为图表指定集合数据容器,然后为
funnelChart
元素定义titleField
和valueField
属性:<chart:funnelChart id="ratingChart" align="MIDDLE_CENTER" dataContainer="ratingDc" height="200px" labelPosition="RIGHT" labelText="[[title]]: [[value]]" marginRight="120" maxLabelWidth="110" marginTop="20" titleField="mechanic" valueField="count" width="500px"> </chart:funnelChart>
-
使用 chart:data 元素。
<chart:funnelChart id="ratingChart" titleField="mechanic" valueField="count"> <chart:data> <chart:item> <chart:property name="mechanic" value="Jack"/> <chart:property name="count" value="1" type="int"/> </chart:item> <chart:item> <chart:property name="mechanic" value="Bob"/> <chart:property name="count" value="2" type="int"/> </chart:item> <chart:item> <chart:property name="mechanic" value="Sam"/> <chart:property name="count" value="3" type="int"/> </chart:item> </chart:data> </chart:funnelChart>
-
-
FunnelChart
事件监听器: -
-
SliceClickListener
– 点击漏斗图的一层。 -
SlicePullInListener
– 漏斗图的一层移回图表。 -
SlicePullOutListener
– 漏斗图的一层移出图表。 -
SliceRightClickListener
– 右键点击漏斗图的一层。
-
更多细节,参阅 AmCharts 文档。
1.6.3. 甘特图
使用 GanttChart
组件可以创建甘特图。
该组件的 XML 名称:chart:ganttChart
-
chart:ganttChart
的元素: -
-
categoryAxis
– 描述分类轴的元素。 -
graph
– 包含chart:graph
元素集合;图形是通过chart:graph
元素进行描述。-
type
属性定义图的类型,可以是:线(line),列(column),步进线(step line),平滑线(smoothed line),蜡烛图(OHLC)以及烛台图(candlestick)。 -
valueField
属性定义数据提供者的键值对列表的键(key)。
-
-
valueAxis
– 图表的值坐标轴。如果图表数据是基于日期或者时间的,可以设置值坐标轴类型为date
。
-
-
chart:ganttChart
的属性: -
-
segmentsField
– 图表的分段字段。 -
additionalSegmentFields
– 需要从数据提供器中获取的对应于实体属性的额外分段字段,跟 additionalFields 属性类似。 -
endField
/endDateField
– 图表的终止值或者终止时间。 -
startField
/startDateField
– 图表的起始值或者起始时间。 -
startDate
– 如果值坐标轴的类型是date
,定义图表的起始时间。 -
categoryField
– 图表的分类字段。
-
- 数据绑定
-
可以为图表指定一个
CollectionContainer
。在下面的例子中,使用实体的start
和end
属性来为 XML 的startDateField
和endDateField
属性赋值。<chart:ganttChart id="ganttChart" additionalSegmentFields="task" balloonDateFormat="JJ:NN" brightnessStep="7" categoryField="category" colorField="color" columnWidth="0.5" dataContainer="taskSpansDc" endDateField="end" height="100%" marginRight="70" period="DAYS" rotate="true" segmentsField="segments" startDate="2016-01-01" startDateField="start" theme="LIGHT" width="100%"> <chart:graph balloonText="<strong>[[task]]</strong>: [[open]] - [[value]]" fillAlphas="1" lineAlpha="1" lineColor="WHITE"/> <chart:valueAxis type="DATE"/> <chart:valueScrollbar autoGridCount="true" color="BLACK"/> <chart:chartCursor cursorAlpha="0" cursorColor="#55bb76" fullWidth="true" valueLineAlpha="0.5" valueBalloonsEnabled="false" valueLineBalloonEnabled="true" valueLineEnabled="true" valueZoomable="true" zoomable="false"/> <chart:export/> </chart:ganttChart>
-
GanttChart
事件监听器: -
-
AxisZoomListener
– 图表坐标轴缩放。 -
CategoryItemClickListener
– 在分类轴点击一个分类。 -
ChartClickListener
– 点击画布。 -
ChartRightClickListener
– 右键点击画布。 -
CursorPeriodSelectListener
– 用光标选择显示周期。 -
CursorZoomListener
– 用光标对图表区域进行缩放。 -
GraphClickListener
– 点击一个图形。 -
GraphItemClickListener
– 点击图形的条目。 -
GraphItemRightClickListener
– 右键点击图形的条目。 -
ZoomListener
– 画布的缩放。
-
更多细节,参阅 AmCharts 文档。
1.6.4. 饼图
使用 PieChart
组件可以创建饼图/多纳圈图。
该组件的 XML 名称:chart:pieChart
- 数据绑定:
-
-
使用数据容器。
可以为图表指定一个
CollectionContainer
。然后为pieChart
元素定义titleField
和valueField
属性:<chart:pieChart id="pieChart" dataContainer="countryLitresDc" height="100%" titleField="country" valueField="litres" width="100%"/>
-
使用 chart:data 元素。
-
-
PieChart
事件监听器: -
-
ChartClickListener
– 点击画布。 -
ChartRightClickListener
– 右键点击画布。 -
SliceClickListener
– 点击饼图的一个分片。 -
SlicePullInListener
– 饼图的一个分片移入图表。 -
SlicePullOutListener
– 饼图的一个分片移出图表。 -
SliceRightClickListener
– 右键点击饼图的一个分片。
-
更多细节,参阅 AmCharts 文档。
1.6.5. 雷达图
使用 RadarChart
组件可以创建雷达/极坐标图。
该组件的 XML 名称:chart:radarChart
- 数据绑定:
-
可以为图表指定一个
CollectionContainer
。然后为radarChart
元素定义categoryField
属性,为嵌套的graph
元素定义valueField
属性:<chart:radarChart id="radarChart" categoryField="country" dataContainer="countryLitresDc" height="100%" startDuration="2" theme="LIGHT" width="100%"> <chart:graphs> <chart:graph balloonText="[[value]] litres of beer per year" bullet="ROUND" valueField="litres"/> </chart:graphs> </chart:radarChart>
-
RadarChart
事件监听器 -
-
AxisZoomListener
– 图表坐标轴缩放。 -
ChartClickListener
– 点击画布。 -
ChartRightClickListener
– 右键点击画布。 -
GraphClickListener
– 点击图形。 -
GraphItemClickListener
– 点击图形的条目。 -
GraphItemRightClickListener
– 右键点击图形的条目。
-
更多细节,参阅 AmCharts 文档。
1.6.6. 序列图
使用 SerialChart
组件可以创建线图、区域图、列图、柱图、步进线图,平滑线图,烛台图以及蜡烛图。图表支持多坐标轴,坐标轴支持简单或者对数刻度,数据点可以等距/非等距展示或者基于时间线展示。
该组件的 XML 名称:chart:serialChart
- 数据绑定:
-
可以为图表指定一个
CollectionContainer
。然后为serialChart
元素定义categoryField
属性,为嵌套的graph
元素定义valueField
属性:<chart:serialChart categoryField="date" dataContainer="dateValueDc"> <chart:graphs> <chart:graph valueField="value" balloonText="[[value]]"> </chart:graph> </chart:graphs> <chart:categoryAxis dashLength="1" minorGridEnabled="true"/> </chart:serialChart>
-
SerialChart
事件监听器 -
-
AxisZoomListener
– 图表坐标轴缩放。 -
CategoryItemClickListener
– 在分类轴点击一个分类。 -
ChartClickListener
– 点击画布。 -
ChartRightClickListener
– 右键点击画布。 -
CursorPeriodSelectListener
– 用光标选择显示周期。 -
CursorZoomListener
– 用光标对图表区域进行缩放。 -
GraphClickListener
– 点击一个图形。 -
GraphItemClickListener
– 点击一个图形条目。 -
GraphItemRightClickListener
– 右键点击一个图形条目。 -
ZoomListener
– 画布的缩放。
-
更多细节,参阅 AmCharts 文档
1.6.7. 股票图
使用 StockChartGroup
组件可以创建股票走势图。
股票图支持多个数据集合并且有开箱即用的数据集合选择器。数据集合可以相互比较。
股票图可以在图上或者坐标轴上展示不同类型的注释。这些注释称为股票事件。
股票图能支持多个股票面板。每个股票面板可以有任意数量的图。每个股票面板是个基于SerialChart的单独序列图,所以能做任何SerialChart可做的事。
-
StockChartGroup
事件监听器 -
-
DataSetSelectorCompareListener
– 数据集合选择器比较事件。 -
DataSetSelectorSelectListener
– 数据集合选择器的选择事件。 -
DataSetSelectorUnCompareListener
– 数据集合选择器取消比较事件。 -
PeriodSelectorChangeListener
– 用光标选择显示周期。 -
StockChartClickListener
– 点击股票图区域。 -
StockChartRightClickListener
– 右键点击股票图区域。 -
StockEventClickListener
– 点击股票事件。 -
StockEventRollOutListener
– 股票事件弹出。 -
StockEventRollOverListener
– 股票事件翻转。 -
StockGraphClickListener
– 点击股票图形。 -
StockGraphItemClickListener
– 点击股票图形条目。 -
StockGraphItemRightClickListener
– 右键点击股票图形条目。 -
StockGraphItemRollOutListener
– 股票图形条目弹出事件。 -
StockGraphItemRollOverListener
– 股票图形条目翻转事件。 -
StockGraphRollOutListener
– 股票图形弹出事件。 -
StockGraphRollOverListener
– 股票图形翻转事件。 -
ZoomListener
– 画布的缩放。
-
1.6.8. 散点图
使用 XYChart
组件可以创建坐标点图/气泡图/散点图。图表支持多个坐标轴,可以使用简单或者对数刻度。
该组件的 XML 名称:chart:xyChart
- 数据绑定:
-
可以为图表指定
CollectionContainer
。然后为嵌套的graph
元素定义xField
和yFields
属性:<chart:xyChart dataContainer="pointPairDc" startDuration="1"> <chart:graphs> <chart:graph balloonText="x:[[x]] y:[[y]]" xField="ax" fillToAxis="x" yField="ay"/> <chart:graph balloonText="x:[[x]] y:[[y]]" fillToAxis="y" xField="bx" yField="by"/> </chart:graphs> <chart:valueAxes> <chart:axis id="x" axisAlpha="0" dashLength="1" position="BOTTOM" title="X Axis"/> <chart:axis id="y" axisAlpha="0" dashLength="1" position="LEFT" title="Y Axis"/> </chart:valueAxes> </chart:xyChart>
-
XYChart
事件监听器 -
-
AxisZoomListener
– 图表轴缩放。 -
ChartClickListener
– 点击画布。 -
CursorPeriodSelectListener
– 用光标选择显示周期。 -
CursorZoomListener
– 用光标对图表区域进行缩放。 -
GraphClickListener
– 点击一个图形 -
GraphItemClickListener
– 点击一个图形条目。 -
GraphItemRightClickListener
– 右键点击一个图形条目。
-
更多细节,参阅 AmCharts 文档。
1.7. 图表使用示例
本章节展示如何使用图表展示扩展。
1.7.1. 配置应用程序项目
-
运行 CUBA Studio,按照 CUBA Studio 用户指南 中 创建新项目 章节的描述创建一个新的项目,项目名称为
sampler
。 -
在 CUBA Studio 中打开 Project Properties : 点击 CUBA → Project Properties 主菜单项。在 App components 列表中添加 charts 应用程序组件。 Studio 如果建议重新创建 Gradle 脚本的时候,点确定。
-
点击 CUBA → Build Tasks → Deploy 。这时, 应用程会被装配并部署到位于
build/tomcat
的 Tomcat 应用程序服务。
以上步骤完成后,展示图表的功能就可以使用了。
1.7.2. 使用简化的数据绑定 API 创建图表
作为第一个示例,我们将创建一个简单的图表,使用简化的数据绑定 API。
在界面添加图表组件然后使用 addData()
方法来填充数据,将带有一组键值对的 MapDataItem
实例作为参数传递给此方法:
<chart:pieChart id="pieChart"
titleField="key"
valueField="value"/>
@Inject
private PieChart pieChart;
@Subscribe
private void onBeforeShow(BeforeShowEvent event) {
pieChart.addData(MapDataItem.of("key", "piece of apple pie",
"value", 70),
MapDataItem.of("key", "piece of blueberry pie",
"value", 20),
MapDataItem.of("key", "piece of cherry pie",
"value", 10));
}
1.7.3. 使用实体创建图表
在本章节我们将创建类似 AmCharts 示例中 3D 重叠列图的图表。这个图将从数据库获取数据,所以必须要定义 dataContainer
属性。amCharts 用来定义这种图所使用的 JavaScript
如下:
var chart = AmCharts.makeChart("chartdiv", {
"theme": "light",
"type": "serial",
"dataProvider": [{
"country": "USA",
"year2004": 3.5,
"year2005": 4.2
}, {
"country": "UK",
"year2004": 1.7,
"year2005": 3.1
}, {
"country": "Canada",
"year2004": 2.8,
"year2005": 2.9
}, {
"country": "Japan",
"year2004": 2.6,
"year2005": 2.3
}, {
"country": "France",
"year2004": 1.4,
"year2005": 2.1
}, {
"country": "Brazil",
"year2004": 2.6,
"year2005": 4.9
}, {
"country": "Russia",
"year2004": 6.4,
"year2005": 7.2
}, {
"country": "India",
"year2004": 8,
"year2005": 7.1
}, {
"country": "China",
"year2004": 9.9,
"year2005": 10.1
}],
"valueAxes": [{
"stackType": "3d",
"unit": "%",
"position": "left",
"title": "GDP growth rate",
}],
"startDuration": 1,
"graphs": [{
"balloonText": "GDP grow in [[category]] (2004): <b>[[value]]</b>",
"fillAlphas": 0.9,
"lineAlpha": 0.2,
"title": "2004",
"type": "column",
"valueField": "year2004"
}, {
"balloonText": "GDP grow in [[category]] (2005): <b>[[value]]</b>",
"fillAlphas": 0.9,
"lineAlpha": 0.2,
"title": "2005",
"type": "column",
"valueField": "year2005"
}],
"plotAreaFillAlphas": 0.1,
"depth3D": 60,
"angle": 30,
"categoryField": "country",
"categoryAxis": {
"gridPosition": "start"
},
"export": {
"enabled": true
}
});
1.7.3.1. 创建一个实体
创建一个 CountryGrowth
实体类。
-
在 CUBA 项目树的 Data Model 部分,单击 New → Entity。 将弹出 New CUBA Entity 对话框窗口。
-
在 Entity name 字段中输入实体类的名称 –
CountryGrowth
,选择 Entity type 为Not persistent
,然后点击 OK 按钮。实体设计器界面将显示在工作区。 -
使用 Entity Designer 添加如下属性:
-
country
,类型是String
-
year2014
,类型是Double
-
year2015
,类型是Double
-
-
切换到 Text 标签页,这个标签页上显示
CountryGrowth
类的源代码。package com.company.sampler.entity; import com.haulmont.chile.core.annotations.MetaClass; import com.haulmont.chile.core.annotations.MetaProperty; import com.haulmont.cuba.core.entity.BaseUuidEntity; @MetaClass(name = "sampler_CountryGrowth") public class CountryGrowth extends BaseUuidEntity { @MetaProperty protected String country; @MetaProperty protected Double year2014; @MetaProperty protected Double year2015; public Double getYear2015() { return year2015; } public void setYear2015(Double year2015) { this.year2015 = year2015; } public Double getYear2014() { return year2014; } public void setYear2014(Double year2014) { this.year2014 = year2014; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; } }
这个类是非持久化实体。这个类的一个实例包含一个国家 2014 和 2015 年的 GDP 增长率。
现在,CountryGrowth
实体类就创建完成了。
1.7.3.1.1. 界面 XML 描述
现在我们创建一个新界面来显示图表。
-
在项目树中选择 Generic UI,在右键菜单中点击 New → Screen。这时会出现模板浏览页面。
-
在可用模板列表中选择 Blank screen,再点击 Next。
-
在 Descriptor name 字段输入
column3d-chart
后点击 Next。 -
打开 Text 标签页,使用下面的内容替换里面的值:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="msg://caption"
messagesPack="com.company.sampler.web"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
<data>
<collection id="countryGrowthDc"
class="com.company.sampler.entity.CountryGrowth"
view="_local"/>
</data>
<layout>
<chart:serialChart id="chart"
angle="30"
categoryField="country"
dataContainer="countryGrowthDc"
depth3D="60"
height="100%"
plotAreaFillAlphas="0.1"
startDuration="1"
width="100%">
<chart:categoryAxis gridPosition="START"/>
<chart:valueAxes>
<chart:axis position="LEFT"
stackType="BOX_3D"
title="GDP growth rate"
unit="%"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph id="graph2014"
balloonText="GDP grow in [[category]] (2014): <b>[[value]]</b>"
fillAlphas="0.9"
lineAlpha="0.2"
title="2014"
type="COLUMN"
valueField="year2014"/>
<chart:graph id="graph2015"
balloonText="GDP grow in [[category]] (2015): <b>[[value]]</b>"
fillAlphas="09."
lineAlpha="0.2"
title="2015"
type="COLUMN"
valueField="year2015"/>
</chart:graphs>
<chart:export/>
</chart:serialChart>
</layout>
</window>
界面描述的根元素包含了一个新的 xmlns:chart
属性:
<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...
>
图表从 dataContainer
属性定义的 countryGrowthDc
数据容器获取数据。名称和数值使用 CountryGrowth
实体的 country
, year2014
和 year2015
属性来展示;这个实体的实例列表保存在数据容器中。
chart:serialChart
组件包含以下属性:
-
angle
- 定义图表的角度。值可以从0
到90
。 -
balloonText
- 定义鼠标浮动到一列时,提示框内的文字。这里可以使用以下标签:[[value]]
,[[title]]
,[[persents]]
,[[description]]
,以及DataProvider
实例中列举的DataItem
的键值,还能使用数据容器中实体属性的名称。如果要使用html
标签,则需要转义。 -
depth3D
- 图表的厚度。跟angle
属性一起使用,可以帮助创建 3D 效果。 -
plotAreaFillAlphas
- 绘图区域的透明度。 -
startDuration
- 动画的持续时间,单位是秒。 -
categoryField
-DataProvider
实例中列举的DataItem
包含的键值对的键值;用来为分类轴定义标签。
chart:serialChart
组件包含下列元素:
-
chart:categoryAxis
- 描述分类轴的元素。-
gridPosition
属性指定网格线的摆放位置,在分类轴单元的中间还是起始处。
-
-
chart:valueAxes
- 定义垂直轴数值的元素。在这里,只使用了一个垂直轴,通过chart:axis
元素描述。-
position
属性定义数值轴跟图表的相对位置。 -
设置
stackType
为BOX_3D
可以让图表展示列柱一个在另一个后面。
-
-
chart:graphs
- 包含chart:graph
元素集合;图形是通过chart:graph
元素进行描述。-
type
属性定义图形类型:线图、列图、步进线图,平滑线图,烛台图以及蜡烛图。 -
valueField
属性定义DataProvider
实例中列举的DataItem
包含的键值对的键值;用来为定义数值。 -
fillAlphas
属性定义填充色的透明度。 -
lineAlpha
属性定义线(或者列边框)的透明度。值域: 0 - 1。
-
-
chart:export
– 可选元素,用来启用图表导出。
1.7.3.1.2. 界面控制器
打开 Column3dChart
界面控制器,然后用下面的代码替换其内容:
package com.company.sampler.web;
import com.company.sampler.entity.CountryGrowth;
import com.haulmont.cuba.gui.model.CollectionContainer;
import com.haulmont.cuba.gui.screen.Screen;
import com.haulmont.cuba.gui.screen.Subscribe;
import com.haulmont.cuba.gui.screen.UiController;
import com.haulmont.cuba.gui.screen.UiDescriptor;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
@UiController("sampler_Column3dChart")
@UiDescriptor("column3d-chart.xml")
public class Column3dChart extends Screen {
@Inject
private CollectionContainer<CountryGrowth> countryGrowthDc;
@Subscribe
private void onInit(InitEvent event) {
List<CountryGrowth> items = new ArrayList<>();
items.add(countryGrowth("USA", 3.5, 4.2));
items.add(countryGrowth("UK", 1.7, 3.1));
items.add(countryGrowth("Canada", 2.8, 2.9));
items.add(countryGrowth("Japan", 2.6, 2.3));
items.add(countryGrowth("France", 1.4, 2.1));
items.add(countryGrowth("Brazil", 2.6, 4.9));
items.add(countryGrowth("Russia", 6.4, 7.2));
items.add(countryGrowth("India", 8.0, 7.1));
items.add(countryGrowth("China", 9.9, 10.1));
countryGrowthDc.setItems(items);
}
private CountryGrowth countryGrowth(String country, double year2014, double year2015) {
CountryGrowth cg = new CountryGrowth();
cg.setCountry(country);
cg.setYear2014(year2014);
cg.setYear2015(year2015);
return cg;
}
}
onInit
方法为 countryGrowthDc
数据容器提供数据。
- 结果
-
现在我们看看创建的界面在真实应用程序中的外观。 选择 CUBA → Start application server 。
-
在登录窗口使用默认凭据登录。点击菜单 Application → Column3dChart ,你将看到类似下图的界面:
1.7.4. 使用 DataProvider 提供的数据创建图表
这个图表通过控制器编码创建的 DataProvider
获取数据,所以并没有定义 dataContainer
属性。
1.7.4.1. 界面 XML 描述
现在我们创建一个新界面来显示图表。
-
在项目树中选择 Generic UI,在右键菜单中点击 New → Screen。这时会出现模板浏览页面。
-
在可用模板列表中选择 Blank screen,再点击 Next。
-
在 Descriptor name 字段输入
stackedarea-chart
后点击 Next。 -
打开 Text 标签页,使用下面的内容替换里面的值:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd"
caption="msg://caption"
messagesPack="com.company.sampler.web"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd">
<layout>
<chart:serialChart id="chart"
categoryField="year"
height="100%"
marginLeft="0"
marginTop="10"
plotAreaBorderAlpha="0"
width="100%">
<chart:chartCursor cursorAlpha="0"/>
<chart:legend equalWidths="false"
periodValueText="total: [[value.sum]]"
position="TOP"
valueAlign="LEFT"
valueWidth="100"/>
<chart:valueAxes>
<chart:axis gridAlpha="0.07"
position="LEFT"
stackType="REGULAR"
title="Traffic incidents"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph fillAlphas="0.6"
hidden="true"
lineAlpha="0.4"
title="Cars"
type=""
valueField="cars"/>
<chart:graph fillAlphas="0.6"
lineAlpha="0.4"
title="Motorcycles"
valueField="motorcycles"/>
<chart:graph fillAlphas="0.6"
lineAlpha="0.4"
title="Bicycles"
valueField="bicycles"/>
</chart:graphs>
<chart:categoryAxis axisColor="#DADADA"
gridAlpha="0.07"
startOnAxis="true"/>
<chart:export/>
</chart:serialChart>
</layout>
</window>
界面描述的根元素包含了一个新的 xmlns:chart
属性:
<window xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...
>
chart:serialChart
属性:
-
categoryField
-DataProvider
实例中列举的DataItem
包含的键值对的键值;用来为分类轴定义标签。
chart:serialChart
的元素:
-
chart:chartCursor
- 可选元素,在图表中添加一个光标。光标跟随鼠标指针并且以提示窗的方式显示图表中相应点的数据。-
cursorAlpha
属性定义光标线的透明度。
-
-
chart:legend
- 定义图表图例的元素。-
position
属性定义图例相对于图表的位置。 -
equalWidths
属性指定是否每个图例条目要跟最宽的那个等宽。 -
periodValueText
属性定义在图例中作为值部分显示的文字,当用户的鼠标指针没有悬浮在任何数据点时显示。这个文字标签需要由两部分构成 - 字段名称(值/开盘/收盘/最高/最低)以及该时间段需要显示的值 - 开盘/收盘/最高/最低/总和/平均/计数。 -
valueAlign
属性定义值文字的对其方式。可能值:left
和right
。 -
valueWidth
属性定义值文字的宽度。
-
-
chart:valueAxes
- 定义垂直轴数值的元素。在这里,只使用了一个垂直轴,通过chart:axis
元素描述。-
position
属性定义数值轴跟图表的相对位置。 -
title
属性定义数值轴标题。 -
设置
stackType
为REGULAR
可以让图表展示滚动值,将该属性设置为none
则显示非滚动值。 -
gridAlpha
定义网格线的透明度。
-
-
chart:graphs
- 包含chart:graph
元素集合;图形是通过chart:graph
元素进行描述。-
type
属性定义图形类型:线图、列图、步进线图,平滑线图,烛台图以及蜡烛图。 -
valueField
属性定义DataProvider
实例中列举的DataItem
包含的键值对的键值;用来为定义数值。 -
fillAlphas
属性定义填充色的透明度。 -
lineAlpha
属性定义线(或者列边框)的透明度。值域: 0 - 1。 -
hidden
属性指定图形是否隐藏
-
-
chart:categoryAxis
- 描述分类轴的元素。-
设置
startOnAxis
为true
会导致直接挨着数值轴开始绘制图表。该属性的默认值是false
,此时,在数值轴和图表之间会有个小间隔。 -
gridAlpha
定义网格线的透明度。 -
axisColor
属性定义轴的颜色。
-
-
chart:export
– 可选元素,用来启用图表导出。
1.7.4.2. 界面控制器
打开 StackedareaChart
界面控制器,然后用下面的代码替换其内容:
package com.company.sampler.web;
import com.haulmont.charts.gui.components.charts.SerialChart;
import com.haulmont.charts.gui.data.DataItem;
import com.haulmont.charts.gui.data.ListDataProvider;
import com.haulmont.charts.gui.data.MapDataItem;
import com.haulmont.cuba.gui.screen.Screen;
import com.haulmont.cuba.gui.screen.Subscribe;
import com.haulmont.cuba.gui.screen.UiController;
import com.haulmont.cuba.gui.screen.UiDescriptor;
import javax.inject.Inject;
@UiController("sampler_StackedareaChart")
@UiDescriptor("stackedarea-chart.xml")
public class StackedareaChart extends Screen {
@Inject
private SerialChart chart;
@Subscribe
private void onInit(InitEvent event) {
ListDataProvider dataProvider = new ListDataProvider();
dataProvider.addItem(transportCount(1994, 1587, 650, 121));
dataProvider.addItem(transportCount(1995, 1567, 683, 146));
dataProvider.addItem(transportCount(1996, 1617, 691, 138));
dataProvider.addItem(transportCount(1997, 1630, 642, 127));
dataProvider.addItem(transportCount(1998, 1660, 699, 105));
dataProvider.addItem(transportCount(1999, 1683, 721, 109));
dataProvider.addItem(transportCount(2000, 1691, 737, 112));
dataProvider.addItem(transportCount(2001, 1298, 680, 101));
dataProvider.addItem(transportCount(2002, 1275, 664, 97));
dataProvider.addItem(transportCount(2003, 1246, 648, 93));
dataProvider.addItem(transportCount(2004, 1318, 697, 111));
dataProvider.addItem(transportCount(2005, 1213, 633, 87));
dataProvider.addItem(transportCount(2006, 1199, 621, 79));
dataProvider.addItem(transportCount(2007, 1110, 210, 81));
dataProvider.addItem(transportCount(2008, 1165, 232, 75));
dataProvider.addItem(transportCount(2009, 1145, 219, 88));
dataProvider.addItem(transportCount(2010, 1163, 201, 82));
dataProvider.addItem(transportCount(2011, 1180, 285, 87));
dataProvider.addItem(transportCount(2012, 1159, 277, 71));
chart.setDataProvider(dataProvider);
}
private DataItem transportCount(int year, int cars, int motorcycles, int bicycles) {
MapDataItem item = new MapDataItem();
item.add("year", year);
item.add("cars", cars);
item.add("motorcycles", motorcycles);
item.add("bicycles", bicycles);
return item;
}
}
onInit
方法将数据作为滚动值提交给了图表。这种类型的图表展示各部分在总和中的占比。
- 结果
-
现在我们看看创建的界面在真实的应用程序中的外观。选择 CUBA → Start application server。
-
在登录窗口使用默认凭据登录。 点击 Application → StackedareaChart 菜单,将看到下图:
1.7.5. 创建带增量数据更新的图表
这种图表从 数据容器 中获取数据,并且数据会被自动更新。当数据容器中添加了新数据时,图表没有完全刷新:数据点每两秒添加一次。此方法非常有用,比如,用来创建自动更新的仪表板。
在此例中,我们将使用 Sales 示例应用程序中的 Order
实体来显示新订单金额的动态。
-
下载 Sales 应用程序然后按照 配置应用程序项目 的描述添加 charts 组件。
-
用 Studio 创建一个新界面,名称为 orders-history,因为要用这个界面来显示新订单条目的历史仪表板。
-
在界面布局中添加
serialChart
组件。要使用增量数据更新功能,我们必须创建一个CollectionContainer
类型的 数据容器 ,并将图表与其绑定。在此示例中,我们不会从数据窗口加载数据,而是动态生成示例数据,因此您无需创建加载器(loader)。设置分类轴的
date
属性和数值轴的amount
属性。<?xml version="1.0" encoding="UTF-8" standalone="no"?> <window xmlns="http://schemas.haulmont.com/cuba/screen/window.xsd" caption="msg://caption" messagesPack="com.company.sales.web" xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"> <data> <collection id="ordersDc" class="com.company.sales.entity.Order" view="_local"/> </data> <layout> <chart:serialChart id="orderHistoryChart" categoryField="date" dataContainer="ordersDc" width="100%"> <chart:graphs> <chart:graph valueField="amount"/> </chart:graphs> </chart:serialChart> </layout> </window>
-
我们将使用 定时器 动态更新图表,定时器是一个特殊的 UI 组件,能将 HTTP 请求发送到服务端。
-
切换到 Designer 标签页。
-
在工具箱的 Non-visual components 分组中选择 Timer 组件。
-
将这个组件拖放到界面组件树(hierarchy)面板。
-
在界面组件树中选中 timer 组件,然后切换到属性面板的 Properties 标签页。
-
给 timer 组件设置 id.
-
比如说数据需要两秒更新一次, 那么我们设置 delay 属性为 2000 毫秒.
-
在 onTimer 定义 java 方法名为
updateChart
。这个方法在 timer 组件每次触发事件时都会调用。 点击 >> 按钮可以在控制器中生成这个方法。 -
选中 repeating 和 autostart 复选框。
Figure 28. 创建定时器
-
-
在处理定时器逻辑之前,先注入必要的依赖:
timeSource
,metadata
和数据源实例。每次触发定时器事件时,我们都会生成一个带有随机价格的新Order
实例。使用includeItem()
方法将新实例添加到数据源。 -
切换到
OrdersHistory
控制器。在开始实现定时器逻辑之前, 注入必要的依赖:timeSource
、metadata
和Order
实体的数据容器。 每次触发计时器事件时,我们会生成一个新的Order
实例,这个实例的 amount 属性使用一个随机值。 使用getMutableItems().add()
方法将新实例添加到集合数据容器中。使用跟创建随机
Order
实例相同的逻辑在onInit()
方法中初始化图表。package com.company.sales.web; import com.company.sales.entity.Order; import com.haulmont.cuba.core.global.Metadata; import com.haulmont.cuba.core.global.TimeSource; import com.haulmont.cuba.gui.components.Timer; import com.haulmont.cuba.gui.model.CollectionContainer; import com.haulmont.cuba.gui.screen.*; import javax.inject.Inject; import java.math.BigDecimal; import java.util.Random; @UiController("sales_OrdersHistory") @UiDescriptor("orders-history.xml") public class OrdersHistory extends Screen { @Inject private Metadata metadata; @Inject private TimeSource timeSource; @Inject private CollectionContainer<Order> ordersDc; private Random random = new Random(42); @Subscribe private void onInit(InitEvent event) { Order initialValue = metadata.create(Order.class); initialValue.setAmount(new BigDecimal(random.nextInt(1000) + 100)); initialValue.setDate(timeSource.currentTimestamp()); ordersDc.getMutableItems().add(initialValue); } public void updateChart(Timer source) { Order orderHistory = metadata.create(Order.class); orderHistory.setAmount(new BigDecimal(random.nextInt(1000) + 100)); orderHistory.setDate(timeSource.currentTimestamp());; ordersDc.getMutableItems().add(orderHistory); } }
此时,图表已经能正常运行,但是数据容器中的实例数量会快速增加,所以我们需要限制显示的条目数量。
Figure 29. 数据每两秒自动更新 -
创建
Queue
的队列。每次触发定时器事件时,生成的条目都会添加到itemsQueue
的顶端。当队列大小超过 10 个时,删掉最早创建的条目。private Queue<Order> itemsQueue = new LinkedList<>();
public void updateChart(Timer source) { Order orderHistory = metadata.create(Order.class); orderHistory.setAmount(new BigDecimal(random.nextInt(1000) + 100)); orderHistory.setDate(timeSource.currentTimestamp());; ordersDc.getMutableItems().add(orderHistory); itemsQueue.add(orderHistory); if (itemsQueue.size() > 10) { Order item = itemsQueue.poll(); ordersDc.getMutableItems().add(item); } }
- 结果
-
所有数据都会以递增方式发送到浏览器。如果在 Chrome 开发者控制台打开 Network 标签页,则会看到我们的网页每 2 秒向后端发送一个 HTTP 请求,并且后端会响应这个请求送回非常小的 JSON 消息。JSON 包含对价格值的一个
add
和remove
操作。所以,并没有重新发送所有数据。
1.7.6. 使用事件
这里看看事件的使用。我们将在界面控制器中创建的界面中添加对图形项目点击事件的处理。在 IDE 中打开界面控制器并且注入图表。为了显示通知,在界面控制器中注入了 Notifications
bean。
@Inject
private Notifications notifications;
@Inject
private SerialChart serialChart;
然后在 onInit
方法的最后添加一个监听器。当图表从 DataProvider
接收数据时,可以使用 getDataItemNN()
方法来取到点击的条目。在此示例中,SerialChart
组件绑定了数据容器,因此应使用另一种方法获取点击的条目:getEntityNN()
:
@Subscribe
private void onInit(InitEvent event) {
chart.addGraphItemClickListener(graphItemClickEvent ->
notifications.create()
.withCaption(itemClickEventInfo(graphItemClickEvent))
.withContentMode(ContentMode.HTML)
.show());
}
private String itemClickEventInfo(Chart.GraphItemClickEvent event) {
CountryGrowth countryGrowth = (CountryGrowth) event.getEntityNN();
return String.format("GDP grow in %s (%s): %.1f%%",
countryGrowth.getCountry(),
event.getGraphId().substring(5),
"graph2014".equals(event.getGraphId()) ? countryGrowth.getYear2014() : countryGrowth.getYear2015());
}
查看结果,使用 Run → Restart application server 重新构建项目然后登录系统。打开界面点击其中一列。
1.7.7. 使用 JSON 配置
需要配置图表,除了使用 XML 属性之外,还可以使用 AmCharts 文档 描述的自定义 JSON。
比如,对于 serialChart:
<chart:serialChart id="serialChart">
<chart:valueAxes>
<chart:axis axisAlpha="0" position="LEFT" title="Incidents"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph id="g1" bullet="ROUND" type="COLUMN" valueField="value"/>
</chart:graphs>
<chart:categoryAxis position="TOP" title="Time" labelsEnabled="false"/>
</chart:serialChart>
这个图有些数据:
@Inject
private SerialChart serialChart;
@Subscribe
private void onInit(InitEvent event) {
ListDataProvider serialChartDataProvider = new ListDataProvider();
int[] serialChartData = {5, 7, 6, 9, 7, 8, 5, 6, 4, 6, 5, 7, 4, 5, 3, 4, 2, 0};
for (int i = 0; i < serialChartData.length; i++) {
serialChartDataProvider.addItem(graphData(serialChartData[i]));
}
serialChart.setDataProvider(serialChartDataProvider);
}
private DataItem graphData(int value) {
MapDataItem item = new MapDataItem();
item.add("value", value);
return item;
}
现在可以改变图表的配置。举个例子,给图表添加一个标题:
serialChart.setNativeJson("{\n" +
" \"titles\": [\n" +
" {\n" +
" \"size\": 15,\n" +
" \"text\": \"Chart Title\"\n" +
" }\n" +
" ]\n" +
"}");
也可以在 XML 设置 JSON 配置:
<chart:serialChart id="serialChart">
<chart:nativeJson>
<![CDATA[
{
"titles": [
{
"size": 15,
"text": "Chart Title"
}
]
}
]]>
</chart:nativeJson>
<chart:valueAxes>
<chart:axis axisAlpha="0" position="LEFT" title="Incidents"/>
</chart:valueAxes>
<chart:graphs>
<chart:graph id="g1" bullet="ROUND" type="COLUMN" valueField="value"/>
</chart:graphs>
<chart:categoryAxis position="TOP" title="Time" labelsEnabled="false"/>
</chart:serialChart>
1.8. 更换 AmCharts 版本
CUBA 框架包含的 AmCharts 库实例可以用另外一个版本替换。步骤:
-
从 AmCharts 网站 下载图表和股票图。
-
将两个图表的
amcharts
目录合并成一个。 -
拷贝
amcharts
目录至{project.rootDir}/modules/web/web/VAADIN/webjars
。 -
重新部署应用程序。
如果需要使用新版本带的新属性,需要按照下面的方式在界面控制器中设置自定义的 JSON。
chart.setNativeJson("{\"valueScrollbar\":{\"autoGridCount\":true}}");
2. 地图展示
CUBA 框架的地图展示子系统是基于集成第三方地图服务提供商。目前,只支持 Google 地图。
2.1. 地图展示功能
-
能响应的事件:
-
鼠标点击。
-
地图平移和缩放。
-
点击和拖动标记。
-
关闭弹窗。
Figure 34. 地图 -
-
添加标记。标记可以是固定位置的或者允许用户拖动的。标记可以处理鼠标点击事件并且发送相应的事件到界面代码中。
Figure 35. 地图标记 -
展示折线和多边形。
Figure 36. 折线 -
绘制多边形。
Figure 37. 多边形 -
热力图渲染。
Figure 38. 热力图
2.2. 配置应用程序项目
为了在应用程序中展示地图,需要添加 charts 应用程序组件,正如在图表展示扩展中描述的。另外,需要为 Web Client block 定义下列应用程序属性:
-
需要定义下列参数之一(这些参数的详细信息,可以参阅 Google 地图 API 文档 ):
-
charts.map.apiKey
– 浏览器的 API 键值。 -
charts.map.clientId
– 客户端 ID。
-
-
可选参数:
-
charts.map.defaultZoom
– 地图的默认缩放级别。 -
charts.map.defaultLatitude
– 默认地图中心的纬度。 -
charts.map.defaultLongitude
– 默认地图中心的经度。 -
charts.map.apiVersion
– 定义使用 Google Map API 的版本。默认值是3.35
。可以设置该属性为3
,这样能用上一个发行版的 API。或者设置成3.exp
,如果需要使用实验版。访问官方 Google Maps API 文档 了解更多信息。
-
web-app.properties
文件示例:
charts.map.apiKey = my_key
charts.map.defaultZoom = 13.0
charts.map.defaultLatitude = 51.5001
charts.map.defaultLongitude = -0.1262
2.3. MapViewer 组件
可以使用 com.haulmont.charts.gui.components.map.MapViewer
组件在应用程序界面中展示地图。
要添加该组件,需要在界面 XML 描述的根元素中声明 chart
命名空间:
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
xmlns:chart="http://schemas.haulmont.com/charts/charts.xsd"
...>
该组件的 XML 名称: mapViewer
。组件声明示例:
<layout>
<vbox id="mapBox" height="100%">
<chart:mapViewer id="map" width="100%" height="100%"/>
</vbox>
</layout>
可以在界面 XML 描述中定义以下组件参数:
-
id
,width
,height
- 标准组件属性。 -
mapType
- 对应于MapViewer.Type
选项的地图类型:roadmap
,satellite
,hybrid
,terrain
。默认值roadmap
。 -
vendor
- 地图服务提供商。目前只支持唯一的值:google
。
地图及其组件的主要配置都在界面控制器中进行,只需要注入在 XML 描述中声明的组件:
@Inject
private MapViewer map;
@Subscribe
protected void onInit(InitEvent event) {
GeoPoint center = map.createGeoPoint(53.490905, -2.249558);
map.setCenter(center);
}
- 地图配置方法
-
-
fitToBounds()
– 设置最小地图缩放比例为:足以展示由东北和西南坐标限制的区域的最小比例。 -
removePolygonVertex()
– 删除多边形的顶点。 -
setCenter()
– 设置地图中心点。 -
setCenterBoundLimits()
– 设置地图中心可能位置的边界。 -
setCenterBoundLimitsEnabled()
– 设置是否应限制地图中心的可能位置。 -
setDraggable()
– 启用/禁用地图拖动模式。 -
setKeyboardShortcutsEnabled()
– 启用/禁用键盘快捷键。 -
setMapType()
– 定义地图类型。 -
setMaxZoom()
– 设置最大可用的地图缩放级别。 -
setMinZoom()
– 设置最小可用的地图缩放级别。 -
setRemoveMessage()
– 设置删除顶点的弹出消息。 -
setScrollWheelEnabled()
– 启用/禁用使用鼠标滚轮缩放地图。 -
setVertexRemovingEnabled()
– 切换是否可以做顶点删除。 -
setVisibleAreaBoundLimits()
– 设置地图可见区域的边界。 -
setVisibleAreaBoundLimitsEnabled()
– 启用可见区域限制模式。 -
setZoom()
– 设置地图缩放级别。
-
- 地图组件接口
-
下列接口可以在
com.haulmont.charts.gui.map.model
包找到。-
Circle
- 展示一个圆圈的组件。Circle
属性跟Polygon
属性类似,除了圆需要用两个额外的属性来定义形状:中心(GeoPoint
)和半径。可以使用MapViewer
接口的createCircle()
和addCircle()
方法来创建此对象并放置在地图上。Circle circle = map.createCircle(center, 130.5); circle.setDraggable(true);; circle.setFillOpacity(0.5); map.addCircleOverlay(circle);
Figure 39. 地图中的圆
-
DrawingOptions
- 辅助绘图组件。目前仅支持绘制多边形。可以通过给MapViewer
传递DrawingOptions
的实例来启用绘图模式。示例:DrawingOptions options = new DrawingOptions(); PolygonOptions polygonOptions = new PolygonOptions(true, true, "#993366", 0.6); ControlOptions controlOptions = new ControlOptions( Position.TOP_CENTER, Arrays.asList(OverlayType.POLYGON)); options.setEnableDrawingControl(true); options.setPolygonOptions(polygonOptions); options.setDrawingControlOptions(controlOptions); options.setInitialDrawingMode(OverlayType.POLYGON); map.setDrawingOptions(options);
-
GeoPoint
- 辅助组件,未在地图上显示。可以使用此组件将地图参数设置为中心点、边界或用来创建更复杂的地图组件。可以使用MapViewer
接口的createGeoPoint()
方法创建该对象。示例:GeoPoint center = map.createGeoPoint(53.490905, -2.249558); map.setCenter(center);
-
HeatMapLayer
- 展示热力图的地图图层,用于显示不同地理位置的数据密度分布,不同数据密度用不同颜色突出显示。默认情况下,密度较高的区域显示为红色,密度较低的区域显示为绿色。可以使用MapViewer
接口的createHeatMapLayer()
和addHeatMapLayer()
方法来创建此对象并放置在地图上。示例:HeatMapLayer heatMapLayer = map.createHeatMapLayer(); List<GeoPoint> data = new ArrayList<>(); data.add(map.createGeoPoint(53.450, -2.090)); data.add(map.createGeoPoint(53.451, -2.095)); data.add(map.createGeoPoint(53.452, -2.092)); data.add(map.createGeoPoint(53.453, -2.093)); data.add(map.createGeoPoint(53.454, -2.093)); data.add(map.createGeoPoint(53.454, -2.092)); data.add(map.createGeoPoint(53.453, -2.092)); heatMapLayer.setData(data); map.addHeatMapLayer(heatMapLayer);
Figure 40. 热力图层可以独立使用
setData()
方法更改热图层的数据。这个改动不需要将图层重新添加到地图中。
-
InfoWindow
- 在弹窗中显示信息的地图组件。可以使用MapViewer
接口的createInfoWindow()
和openInfoWindow()
方法来创建此对象并放置在地图上。示例:InfoWindow w = map.createInfoWindow("Some text"); map.openInfoWindow(w);
信息窗口可以绑定到标记上,示例:
map.addMarkerClickListener(event -> { Marker marker = event.getMarker(); String caption = String.format("Marker clicked: %.2f, %.2f", marker.getPosition().getLatitude(), marker.getPosition().getLongitude()); InfoWindow w = map.createInfoWindow(caption, marker); map.openInfoWindow(w); });
Figure 41. 信息窗口
-
Label
- 在地图上显示文本标签的组件。可以使用
MapViewer
接口的createLabel()
和addLabel()
方法来创建Label
对象并放置在地图上。标签可以使用removeLabel()
按顺序删除。样式方面,标签支持 HTML 标签。Label
组件有下列属性:-
value
- 标签的字符串值。如果标签内容类型设置为HTML
,则浏览器将解析标签值。 -
position
-GeoPoint
的实现,表示标签的地理位置。 -
contentType
- 设置标签是否可以作为 HTML 来解析。可以有两个可能值:PLAIN_TEXT
和HTML
。 -
adjustment
- 设置标签相对于GeoPoint
位置标记的调整位置。 -
styleName
- 为标签设置额外的样式名称。Label label = map.createLabel(); label.setValue("<span style=\"color: #ffffff; font-size: 24px;\">White label</span>"); label.setPosition(map.createGeoPoint(42.955, 32.883)); label.setAdjustment(Label.Adjustment.BOTTOM_CENTER); label.setContentType(Label.ContentType.HTML); map.addLabel(label);
Figure 42. 地图标签
-
-
Marker
- 标记地图上位置的组件。默认情况下,使用地图服务供应商的标准图标。可以使用MapViewer
接口的createMarker()
和addMarker()
方法来创建此对象并放置在地图上。示例:Marker marker = map.createMarker("My place", map.createGeoPoint(53.590905, -2.249558), true); marker.setClickable(true); map.addMarker(marker);
clearMarkers()
方法顺序删除地图上的所有标记。MarkerImage
接口用来设置标记图标或者阴影图像。MarkerImage markerImage = map.createMarkerImage("https://www.cuba-platform.com/sites/logo.png"); GeoPoint center = map.createGeoPoint(21.11, -76.20); markerImage.setSize(map.createSize(44, 44)); markerImage.setOrigin(map.createPoint(0, 0)); markerImage.setAnchor(map.createPoint(-5, 50)); Marker marker = map.createMarker("Cuba", center, true, markerImage); map.addMarker(marker);
Figure 43. 标记图片
-
Polyline
- 展示折线的组件。可以使用MapViewer
接口的createPolyline()
和addPolyline()
方法来创建此对象并放置在地图上。示例:List<GeoPoint> coordinates = new ArrayList<>(); coordinates.add(map.createGeoPoint(53.4491, -1.9955)); coordinates.add(map.createGeoPoint(53.6200, -1.9539)); coordinates.add(map.createGeoPoint(53.4425, -1.6196)); coordinates.add(map.createGeoPoint(53.1900, -1.4969)); coordinates.add(map.createGeoPoint(53.1926, -1.6197)); Polyline polyline = map.createPolyline(coordinates); polyline.setStrokeWeight(5); polyline.setStrokeOpacity(0.5); polyline.setStrokeColor("#7341f4"); map.addPolyline(polyline);
Figure 44. 折线
-
Polygon
- 展示多边形的组件。可以使用MapViewer
接口的createPolygon()
和addPolygonOverlay()
方法来创建此对象并放置在地图上。示例:List<GeoPoint> coordinates = new ArrayList<>(); coordinates.add(map.createGeoPoint(48.560579, 7.767876)); coordinates.add(map.createGeoPoint(48.561386, 7.782791)); coordinates.add(map.createGeoPoint(48.541940, 7.782861)); coordinates.add(map.createGeoPoint(48.545641, 7.768749)); Polygon p = map.createPolygon(coordinates, "#9CFBA9", 0.6, "#2CA860", 1.0, 2); map.addPolygonOverlay(p);
Figure 45. 多边形
-
- 事件监听器
-
下列监听器都在
com.haulmont.charts.gui.map.model.listeners
包内。-
CircleCenterChangeListener
- 用户在地图编辑模式改变了圆的中心点位置。 -
CircleCompleteListener
- 用户在地图编辑模式创建了一个圆。 -
CircleRadiusChangeListener
- 用户在地图编辑模式改变了一个圆的半径。 -
InfoWindowClosedListener
- 用户关闭了一个信息窗口。 -
MapInitListener
- 地图初始化完成。在加载所有图层并且所有坐标可用时,第一次加载地图后调用此监听器一次。 -
MapMoveListener
- 用户鼠标按下并且拖动了地图。 -
MarkerDragListener
- 用户拖动了一个标记。 -
PolygonCompleteListener
- 用户在地图编辑模式创建了一个多边形。 -
PolygonEditListener
- 用户编辑了多边形(移动或者添加顶点)。
左键点击事件:
-
CircleClickListener
- 用户点击圆。 -
MapClickListener
- 用户点击地图。 -
MarkerClickListener
- 用户点击标记。 -
PolygonClickListener
- 用户点击多边形。
右键点击事件:
-
CircleRightClickListener
- 用户右键点击圆。 -
MapRightCLickListener
- 用户右键点击地图。 -
MarkerRightClickListener
- 用户右键点击标记。 -
PolygonRightClickListener
- 用户右键点击多边形。
双击事件监听器:
-
MarkerDoubleClickListener
- 用户双击标记。 -
CircleDoubleClickListener
- 用户双击圆。
-
想了解更多关于地图方法和参数的细节信息,请参阅相应的 JavaDoc 文档。
3. 透视表展示
PivotTable
是带有拖拽功能的表格组件,通过这个组件可以将数据集合转换成汇总表格,并且可以通过 2D 的拖拽 UI 来操作。在 CUBA Studio 组件库就可以使用该组件的全部功能。
PivotTable
基于外部 JavaScript 库 - https://github.com/nicolaskruchten/pivottable 。可以在作者的网站上找到更多关于 PivotTable
的例子: http://nicolas.kruchten.com/pivottable/examples/ 。
该组件的 XML 名称: pivotTable
实现该组件的 block: Web Client
在界面 XML 描述中定义组件的示例:
<chart:pivotTable id="tipsPivotTable"
dataContainer="tipsDc"
renderer="HEATMAP">
<chart:properties>
<chart:property name="row"/>
<chart:property name="totalBill"/>
<chart:property name="tip"/>
<chart:property name="sex"/>
<chart:property name="smoker"/>
<chart:property name="day"/>
<chart:property name="time"/>
<chart:property name="size"/>
</chart:properties>
<chart:aggregation mode="SUM_OVER_SUM">
<chart:property name="tip"/>
<chart:property name="totalBill"/>
</chart:aggregation>
<chart:rows>
<chart:row value="sex"/>
<chart:row value="smoker"/>
</chart:rows>
<chart:columns>
<chart:column value="day"/>
<chart:column value="time"/>
</chart:columns>
<chart:sortersFunction>
function(attr){
if(attr=="Day"){
return $.pivotUtilities.sortAs(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]);
}
}
</chart:sortersFunction>
</chart:pivotTable>
- pivotTable 的 XML 元素
-
properties
- 在pivotTable
内使用的一组属性的键值对映射。键是 数据容器 中属性的名称,值是本地化语言的名称。
-
derivedProperties
- 可以向原始数据容器添加新属性,这些属性派生自现有属性。此元素是键值映射,其中键是生成的属性的名称,值是生成此属性的 JavaScript 函数。-
元素内部的
derivedProperty
元素需要定义caption
属性,此属性的值会被当作键值使用。 -
function
元素用作derivedProperty
的值。
-
-
columns
- 作为表格列使用的一组属性。该属性值可以设置为properties
的键值或者生成属性的名称。
-
columnOrder
- 渲染时列数据的展示顺序。
-
rows
- 作为表格行使用的一组属性。该属性值可以设置为properties
的键值或者生成属性的名称。
-
rowOrder
- 渲染时行数据的展示顺序。
-
exclusions
- 键值映射,其中键是属性的名称(properties
键值或生成的属性的名称),值是要在渲染时不包括的属性值列表。该属性只对可编辑的pivotTable
有效。
-
inclusions
- 键值映射,其中键是属性的名称(properties
键值或生成的属性的名称),值是要渲染的属性值列表。该属性只对可编辑的pivotTable
有效。
-
filterFunction
- JavaScript 函数,用来做过滤。
-
renderers
- 定义渲染函数的集合,这个集合需要在 UI 中的可用渲染器列表中显示。-
default
属性用来设置一个默认的渲染器。当组件加载时,选择的渲染器会当作默认的使用。 -
内部的
renderer
元素可以使用type
属性来设置一个预制的渲染器:AREA_CHART
、BAR_CHART
、COL_HEATMAP
、HEATMAP
、HORIZONTAL_BAR_CHART
、HORIZONTAL_STACKED_BAR_CHART
、LINE_CHART
、ROW_HEATMAP
、SCATTER_CHART
、STACKED_BAR_CHART
、TABLE_BAR_CHART
、TABLE
、TREEMAP
、TSV_EXPORT
。只对可编辑的
pivotTable
有效。
-
-
rendererOptions
- 定义渲染器的参数。事实上只有两种渲染器能做自定义设置:-
全部的
heatmap
渲染器。可以通过 JavaScript 代码设置热力单元的颜色。 -
全部的
chart
渲染器。参数可以用来设置图表的大小。
-
-
sortersFunction
- JavaScript 函数,用来做行和列标题的排序。
- pivotTable 的聚合(aggregation)属性
-
aggregation
- 设置聚合函数,用来对每个单元格的结果做聚合。aggregation
属性:-
mode
属性可以用来设置一个预制的聚合函数。 -
caption
展示在 UI 的本地化语言的描述。 -
custom
- 如果是true
,那么会忽略mode
的值,而使用 内部的function
元素指定的 JavaScript 函数。aggregation
元素: -
function
- 包含聚合函数的 JavaScript 代码。 -
property
- 用来作为聚合函数输入参数的属性列表。该属性值可以设置为properties
的键值或者生成属性的名称。只对非可编辑pivotTable
有效。示例:
<chart:aggregation mode="SUM_OVER_SUM" custom="true"> <chart:property name="tip"/> <chart:property name="Total Bill"/> </chart:aggregation>
-
-
aggregationProperties
- 定义在聚合器的下拉列表中显示的属性列表。该属性值可以设置为properties
的键值或者生成属性的名称。只对可编辑pivotTable
有效。<chart:aggregationProperties> <chart:property name="tip"/> <chart:property name="totalBill"/> </chart:aggregationProperties>
-
aggregations
- 定义需要在 UI 中的可用聚合器下拉列表中显示的聚合器集合。aggregations
属性:-
default
属性用来设置一个预制的聚合函数。当组件加载时,选择的函数会当作默认的使用。 -
内部的
aggregation
元素跟 aggregation 的使用方法相同,除了内部的property
元素。只对可编辑pivotTable
有效。示例:
<chart:aggregations default="COUNT"> <chart:aggregation caption="Count"/> <chart:aggregation mode="SUM_OVER_SUM"/> </chart:aggregations>
-
- pivotTable 属性
-
dataContainer
- 设置在界面 XML 描述的data
部分定义的一个数据容器。必须是collectionDataContainer
类型。
-
editable
- 如果是true
,UI 会显示用来操作数据的元素,否则只显示数据。
-
renderer
- 启用设置一个预制的数据渲染器。只对非可编辑pivotTable
有效。
-
showColTotals
- 定义是否显示列总数。默认值是true
。只对表格渲染器有效。
-
showRowTotals
- 定义是否显示行总数。默认值是true
。只对表格渲染器有效。
-
showUI
- 控制是否在可编辑的透视表中显示 UI 元素。默认值是true
。
-
autoSortUnusedProperties
- 定义在 UI 是否要对没使用的属性进行排序。只对可编辑pivotTable
有效。
-
unusedPropertiesVertical
- 定义没使用的属性是要以垂直方式展示(true
)还是以水平方式展示(false
或者默认情况)。如果设置为数字,那么当属性名称的字符组合长度超过此数字,则属性将垂直显示。
- pivotTable 的监听器
-
addCellClickListener
- 为PivotTable
添加单元格点击事件监听器。CellClickEvent
事件只在表格渲染器会触发(TABLE
,HEATMAP
,TABLE_BAR_CHART
,COL_HEATMAP
,ROW_HEATMAP
)。tipsPivotTableUI.addCellClickListener(event -> { showNotification("Value: " + event.getValue() + ",\n" + "Filters applied: " + event.getFilters()); });
-
addRefreshListener
- 为PivotTable
添加刷新事件监听器。RefreshEvent
事件只在可编辑PivotTable
会触发。tipsPivotTableUI.addRefreshListener(event -> { showNotification("Row order :" + event.getRowOrder() + ",\n" + "Inclusions: " + event.getInclusions()); });
RefreshEvent
事件中有下列值可用: aggregation, aggregationProperties, columns, columnOrder, exclusions, inclusions, renderer, rowOrder, rows.
- pivotTable 的属性
-
autoSortUnusedProperties - dataContainer - editable - height - menuLimit - renderer - unusedPropertiesVertical - width
- pivotTable 的元素
-
aggregation - aggregationProperties - aggregations - columnOrder - columns - derivedProperties - exclusions - filterFunction - hiddenFromAggregations - hiddenFromDragDrop - hiddenProperties - inclusions - properties - rendererOptions - renderers - rowOrder - rows - sortersFunction
- API
3.1. 透视表示例
3.1.1. 自定义聚合器和派生属性
下面是 pivotTable
的一个示例,与上面示例的不同之处在于使用了自定义的聚合器以及在界面的 Java 控制器中添加的派生属性。
<chart:pivotTable id="tipsCustomAggregatorPivotTable"
dataContainer="tipsDc">
<chart:properties>
<chart:property name="row"/>
<chart:property name="totalBill"/>
<chart:property name="tip"/>
<chart:property name="sex"/>
<chart:property name="smoker"/>
<chart:property name="day"/>
<chart:property name="time"/>
<chart:property name="size"/>
</chart:properties>
<chart:aggregation mode="SUM_OVER_SUM" custom="true">
<chart:property name="tip"/>
<chart:property name="Total Bill"/>
</chart:aggregation>
<chart:rows>
<chart:row value="sex"/>
<chart:row value="Smokes"/>
</chart:rows>
<chart:columns>
<chart:column value="day"/>
<chart:column value="time"/>
</chart:columns>
</chart:pivotTable>
可以在 XML 描述或 Java 控制器中设置排序和聚合函数。在此例中,JavaScript 函数作为参数传递给 JsFunction
类的构造器。
派生属性也可以在界面控制器中定义。
public class PivotSampleScreen extends Screen {
@Inject
private PivotTable tipsCustomAggregatorPivotTable;
@Subscribe
protected void onInit(InitEvent event) {
tipsCustomAggregatorPivotTable.setSortersFunction(
new JsFunction("function(attr){if(attr == \"Day\"){return $.pivotUtilities.sortAs([\"Mon\",\"Tue\",\"Wed\",\"Thu\",\"Fri\",\"Sat\",\"Sun\"]);}}"));
tipsCustomAggregatorPivotTable.getAggregation().setFunction(
new JsFunction("$.pivotUtilities.aggregators[\"Sum\"]([\"Tip\"])"));
DerivedProperties derivedProperties = new DerivedProperties();
derivedProperties.addAttribute("Smokes",
new JsFunction("function(record) {return record.smoker == \"Yes\" ? \"True\" : \"False\";}"));
tipsCustomAggregatorPivotTable.setDerivedProperties(derivedProperties);
}
}
运行结果:
3.1.2. 可编辑的透视表
在下面的示例中,让 pivotTable
可编辑并设置默认聚合函数。在可编辑模式下,可以直接在 UI 中更改外观(图表类型)和表格内容(行和列)。
<chart:pivotTable id="tipsPivotTableUI"
autoSortUnusedProperties="true"
dataContainer="tipsDc"
editable="true">
<chart:properties>
<chart:property name="row"/>
<chart:property name="totalBill"/>
<chart:property name="tip"/>
<chart:property name="sex" localizedName="Sex"/>
<chart:property name="smoker"/>
<chart:property name="day"/>
<chart:property name="time"/>
<chart:property name="size"/>
</chart:properties>
<chart:hiddenProperties>
<chart:property name="row"/>
</chart:hiddenProperties>
<chart:aggregationProperties>
<chart:property name="tip"/>
<chart:property name="totalBill"/>
</chart:aggregationProperties>
<chart:aggregations default="COUNT">
<chart:aggregation caption="Count"/>
<chart:aggregation mode="SUM_OVER_SUM"/>
</chart:aggregations>
<chart:renderers default="BAR_CHART"/>
<chart:rows>
<chart:row value="sex"/>
<chart:row value="smoker"/>
</chart:rows>
<chart:columns>
<chart:column value="day"/>
<chart:column value="time"/>
</chart:columns>
<chart:sortersFunction>
function(attr){
if(attr=="Day"){
return $.pivotUtilities.sortAs(["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]);
}
}
</chart:sortersFunction>
</chart:pivotTable>
3.2. 导出透视表数据
PivotTableExtension
是 PivotTable
组件的扩展,提供带有聚合数据的表格下载 API,下载格式为 XLS。
需要使用类构造器(而不是 UiComponents
bean)在界面控制器中创建此扩展的实例。示例:
@Inject
private PivotTable pivotTable;
private PivotTableExtension extension;
@Subscribe
private void onInit(InitEvent event) {
extension = new WebPivotTableExtension(pivotTable)
}
Tip
|
该扩展仅适用于以下渲染器类型:TABLE,TABLE_BAR_CHART,HEATMAP,COL_HEATMAP,ROW_HEATMAP,并且不能取到单元格的颜色。 |
可以使用 exportTableToXls()
方法下载 XLS 格式的表格数据,比如,在点击按钮时:
extension.exportTableToXls();
默认情况下,下载文件名跟 PivotTable
数据容器中实体的本地化名称一致。也可以使用 setFileName()
方法定义文件名:
extension.setFileName("Orders of " + new Date());
Tip
|
XLS 格式的文件最多只能存 65536 行数据。如果 |
另外,PivotTableExtension
提供了另外两个获取 PivotTable
数据的方法:
-
JSON 格式:
extension.getPivotDataJSON();
-
序列化的
PivotData
类对象:extension.getPivotData();
3.3. 使用 ShowPivotAction
ShowPivotAction
是一个特殊的操作,可以通过这个操作从继承了 ListComponent
的组件中导出数据,比如 Table
,Tree
以及 DataGrid
,甚至透视表。此操作不需要其它任何额外的应用程序组件就可以提供简单的 BI 分析方法。
这个操作需要在界面控制器中以编程的方式创建并使用,比如,在按钮中:
ShowPivotAction showPivotAction = new ShowPivotAction(tipsGroupTable);
exportButton.setAction(showPivotAction);
ShowPivotAction
有两种导出模式:所有行和选中行。如果没有选中行,默认会不进行确认导出所有行。
可编辑的 PivotTable
组件会显示在新标签页中。默认情况下,包含在组件数据容器视图的所有属性都会被展示,除了下面这些:
-
集合(Collection)类型的属性;
-
字节(byte)数组类型的属性;
-
UUID 属性;
-
带有
@SystemLevel
注解的属性。
如果需要排除某些属性或者只包含部分属性,可以通过下面的流式 API 方法来实现:
-
withIncludedProperties()
,示例:ShowPivotAction showPivotAction = new ShowPivotAction(tipsGroupTable) .withIncludedProperties(Arrays.asList("sex", "smoker", "day", "totalBill"));
-
withExcludedProperties()
,示例:ShowPivotAction showPivotAction = new ShowPivotAction(tipsGroupTable) .withExcludedProperties(Arrays.asList("sex", "smoker"));
这些方法接收属性名称的列表作为输入参数,所有不正确的属性名称将被忽略。
可以使用 withNativeJson()
方法修改透视表的默认配置,此方法接收 JSON 字符串作为输入。注意要使用本地化的属性名称:
ShowPivotAction showPivotAction = new ShowPivotAction(tipsGroupTable)
.withNativeJson("{" +
" \"cols\": [\"Time\", \"Day\"]," +
" \"rows\": [\"Sex\", \"Smoker\"]," +
" \"editable\": false," +
" \"renderer\": \"heatmap\"," +
" \"aggregation\": {" +
" \"id\": \"d8fc3fdf-730d-c94f-a0c8-72a9ce3dcb3a\"," +
" \"mode\": \"count\"," +
" \"properties\": [\"Sex\"]" +
" }" +
" }");
以下是不可编辑透视表的 JSON 结构:
{
"cols": ["localized property", "localized property"],
"rows": ["localized property"],
"editable": false,
"renderer": "heatmap",
"aggregation": {
"id": "d8fc3fdf-730d-c94f-a0c8-72a9ce3dcb3a",
"mode": "sumOverSum",
"properties": ["localized property", "localized property"]
}
}
这是可编辑透视表的 JSON 结构:
{
"cols": ["localized property"],
"rows": ["localized property"],
"editable": true,
"renderers": {
"selectedRenderer": "barChart"
},
"autoSortUnusedProperties": true,
"aggregationProperties": ["localized property", "localized property"],
"aggregations": {
"selectedAggregation": "count",
"aggregations": [{
"id": "647780f0-c6d0-6ade-a63a-542b5c8cdbd5",
"mode": "count",
"caption": "Count"
}, {
"id": "c2663238-2654-67f0-2dec-add6962d867c",
"mode": "sumOverSum"
}]
}
}
显示的透视数据可以轻松导出到 Excel(如果支持当前渲染器)。默认情况下,在打开的标签页中将显示相应的导出按钮。