Difference between revisions of "Plugin: ZK Charts Components"
From iDempiere en
| Line 1: | Line 1: | ||
*'''Creator:''' [[User:JamesChu|James Chu]] | *'''Creator:''' [[User:JamesChu|James Chu]] | ||
*'''SPONSOR:''' [https://www.zkoss.org/ zkoss.org] | *'''SPONSOR:''' [https://www.zkoss.org/ zkoss.org] | ||
| − | *'''License:''' | + | *'''License:''' The plugin source code is licensed under the GNU [http://www.gnu.org/licenses/gpl-2.0.html GPLv2] or later and contains no ZK binaries. See [[#Licensing|Licensing]] for what that means in practice. |
*'''Source:''' [https://github.com/zkoss-demo/zkoss-idempiere-addon-plugin GitHub repository] | *'''Source:''' [https://github.com/zkoss-demo/zkoss-idempiere-addon-plugin GitHub repository] | ||
| − | *''' | + | *'''Supported branches:''' <code>main</code> for iDempiere 13, [https://github.com/zkoss-demo/zkoss-idempiere-addon-plugin/tree/v12 <code>v12</code>] for iDempiere 12. |
*'''Related:''' [[Plugin: ZK Pivottable Components]] – lives in the same repository and builds on this one. | *'''Related:''' [[Plugin: ZK Pivottable Components]] – lives in the same repository and builds on this one. | ||
==Description== | ==Description== | ||
| − | *This plugin enables iDempiere implementors to use '''ZK Charts components''' in iDempiere without modifying iDempiere core. It is designed as an optional add-on: you can install | + | *This plugin enables iDempiere implementors to use '''ZK Charts components''' in iDempiere without modifying iDempiere core. It is designed as an optional add-on: you can install and uninstall it as a standard iDempiere OSGi plugin. |
*It covers two ways of using ZK Charts: | *It covers two ways of using ZK Charts: | ||
*#'''Globally''' – replace the chart rendering iDempiere already does, so that every existing dashboard chart, performance goal and chart field is drawn with ZK Charts, without changing a single application dictionary record. | *#'''Globally''' – replace the chart rendering iDempiere already does, so that every existing dashboard chart, performance goal and chart field is drawn with ZK Charts, without changing a single application dictionary record. | ||
*#'''In a dashboard''' – a sales and inventory dashboard that redraws itself through ZK server push whenever an order or shipment is saved. | *#'''In a dashboard''' – a sales and inventory dashboard that redraws itself through ZK server push whenever an order or shipment is saved. | ||
| − | * | + | *'''Nothing is one-way.''' Uninstalling the bundle silently restores the core rendering, and any exception during rendering makes the service return <code>false</code> so that iDempiere falls through to the next renderer rather than showing an empty panel. |
[[File:Zkcharts-renderer.png|thumb|center|600px|An existing AD_Chart rendered with ZK Charts]] | [[File:Zkcharts-renderer.png|thumb|center|600px|An existing AD_Chart rendered with ZK Charts]] | ||
[[File:Zkcharts-dashboard.png|thumb|center|600px|The live sales and inventory dashboard]] | [[File:Zkcharts-dashboard.png|thumb|center|600px|The live sales and inventory dashboard]] | ||
| + | |||
| + | ==Why ZK Charts rather than the renderer already in core== | ||
| + | *iDempiere 13 ships billboard.js in core at no cost, and it is a perfectly capable client-side chart library. The honest comparison is narrower than "static images versus interactive charts" – that difference is against '''JFreeChart''', which is deprecated in v13. | ||
| + | {| class="wikitable" | ||
| + | ! !! JFreeChart ''(deprecated in v13)'' !! billboard.js ''(v13 default)'' !! ZK Charts | ||
| + | |- | ||
| + | | Rendering || server-side PNG image || client-side SVG || client-side SVG | ||
| + | |- | ||
| + | | Interactive tooltips || – || yes || yes | ||
| + | |- | ||
| + | | Legend toggling || – || yes || yes | ||
| + | |- | ||
| + | | Entry animation || – || yes || yes | ||
| + | |- | ||
| + | | Export the chart as PNG / SVG / PDF / CSV || – || – || '''built in''', from the chart's own context menu | ||
| + | |- | ||
| + | | Click-to-zoom to the underlying records || yes || yes || yes | ||
| + | |- | ||
| + | | <code>AD_Chart</code> chart types covered || all || all || all | ||
| + | |- | ||
| + | | Java API available to '''your own''' plugin || the JFreeChart API || the <code>Billboard</code> component: title, type, orientation, legend, axis labels, series colours, time series || the full <code>org.zkoss.chart</code> model – plot options, per-point markers and styling, multiple axes, chart-level events, accessibility descriptions | ||
| + | |- | ||
| + | | Accessibility descriptions per point/series || – || – || yes | ||
| + | |- | ||
| + | | Support || community || community || commercial, under the ZK Charts licence | ||
| + | |- | ||
| + | | Cost || free || free || commercial licence, evaluation available | ||
| + | |} | ||
| + | *If all you need is a readable chart on a dashboard, billboard.js already does that. The two reasons to add this plugin are '''export straight from the chart''' and '''the much larger API surface when you build charts in your own forms''' – plus commercial support on the component itself. | ||
==Requirements== | ==Requirements== | ||
| Line 20: | Line 49: | ||
! Item !! Version | ! Item !! Version | ||
|- | |- | ||
| − | | iDempiere || 13 | + | | iDempiere || 13 ''(use the <code>v12</code> branch for iDempiere 12)'' |
|- | |- | ||
| Java runtime || 17 | | Java runtime || 17 | ||
| Line 29: | Line 58: | ||
|} | |} | ||
| − | ==Components== | + | ==Installation== |
| + | *Obtain the three jars – see [[#Building from source|Building from source]]. <!-- TODO: replace with a direct link once fragment/renderer/dashboard jars are published under GitHub Releases; today the repository has no releases and no tags, so "download the release" cannot be followed. --> | ||
| + | *'''The order matters''' – a fragment only takes effect after its host bundle is re-resolved, which means a restart: | ||
| + | *#Install <code>org.idempiere.zkcharts.fragment</code> through the Felix Web Console (<code>/osgi/system/console/bundles</code>). | ||
| + | *#'''Restart the iDempiere runtime.''' | ||
| + | *#Install <code>org.idempiere.zkcharts.renderer</code> and/or <code>org.idempiere.zkcharts.dashboard</code>. | ||
| + | *#On the '''Bundles''' page, confirm the fragment shows as ''Fragment'' and the plugins as ''Active'' – not merely ''Resolved''. | ||
| + | *#Log out and back in, so the menu tree is rebuilt with the entries the plugin adds. | ||
| + | *The dashboard plugin adds its menu entries through a 2Pack applied by its bundle activator; no manual import is required. | ||
| + | |||
| + | ==Usage== | ||
| + | |||
| + | ===The client you log in as matters=== | ||
| + | *Every chart is scoped to the logged in client, and most of them to completed sales orders. | ||
| + | *<code>SuperUser</code> signs in to the '''System''' client (<code>AD_Client_ID = 0</code>), which by design holds the dictionary and no business data at all – so every chart is legitimately empty and nothing is broken. | ||
| + | *Log in as <code>GardenAdmin</code> to the '''GardenWorld''' client instead. | ||
| + | |||
| + | ===Using ZK Charts in your own plugin=== | ||
| + | *This is the part most plugin developers come for. There are three pieces, and the third one is the rule that follows from the fragment design. | ||
| + | *'''1. Compile-time dependency.''' Add the ZK Evaluation repository and the ZK Charts jar to your bundle's <code>pom.xml</code>. Tycho copies it onto the compile classpath; it is '''not''' embedded in your jar. | ||
| + | <syntaxhighlight lang="xml"> | ||
| + | <repositories> | ||
| + | <repository> | ||
| + | <id>ZK PE/EE Evaluation</id> | ||
| + | <url>https://mavensync.zkoss.org/eval/</url> | ||
| + | </repository> | ||
| + | </repositories> | ||
| + | <dependencies> | ||
| + | <!-- Compile time only: at runtime the classes come from | ||
| + | org.idempiere.zkcharts.fragment through org.adempiere.ui.zk --> | ||
| + | <dependency> | ||
| + | <groupId>org.zkoss.chart</groupId> | ||
| + | <artifactId>zkcharts</artifactId> | ||
| + | <version>12.5.0.0-Eval</version> | ||
| + | </dependency> | ||
| + | </dependencies> | ||
| + | </syntaxhighlight> | ||
| + | *'''2. Runtime wiring in <code>META-INF/MANIFEST.MF</code>.''' You do '''not''' import <code>org.zkoss.chart</code> directly. The fragment exports those packages ''through its host'', so requiring the host bundle is what makes them visible: | ||
| + | <syntaxhighlight lang="text"> | ||
| + | Require-Bundle: org.adempiere.base;bundle-version="13.0.0", | ||
| + | org.adempiere.ui.zk;bundle-version="13.0.0", | ||
| + | zk;bundle-version="10.0.1", | ||
| + | zul;bundle-version="10.0.1" | ||
| + | </syntaxhighlight> | ||
| + | *'''3. The rule.''' You compile against a jar on the Maven classpath but resolve at runtime through the fragment – so '''your bundle will not resolve unless <code>org.idempiere.zkcharts.fragment</code> is installed and the runtime has been restarted since'''. A bundle stuck at ''Resolved'' or ''Installed'' is almost always this. | ||
| + | *'''A working ZUL.''' <code><charts></code> is a normal ZK component once the fragment is in place: | ||
| + | <syntaxhighlight lang="xml"> | ||
| + | <?xml version="1.0" encoding="UTF-8"?> | ||
| + | <zk> | ||
| + | <window apply="org.example.myplugin.MyChartComposer"> | ||
| + | <charts id="chart" type="spline" title="Monthly Average Temperature"/> | ||
| + | </window> | ||
| + | </zk> | ||
| + | </syntaxhighlight> | ||
| + | <syntaxhighlight lang="java"> | ||
| + | public class MyChartComposer extends SelectorComposer<Component> { | ||
| + | @Wire private Charts chart; | ||
| + | |||
| + | @Override | ||
| + | public void doAfterCompose(Component comp) throws Exception { | ||
| + | super.doAfterCompose(comp); | ||
| + | chart.getYAxis().getTitle().setText("Temperature (°C)"); | ||
| + | chart.getTooltip().setShared(true); | ||
| + | |||
| + | Series tokyo = chart.getSeries(); | ||
| + | tokyo.setName("Tokyo"); | ||
| + | tokyo.getMarker().setSymbol("square"); | ||
| + | for (double v : new double[] {5.2, 5.7, 8.7, 13.9, 18.2, 21.4, 25.0}) | ||
| + | tokyo.addPoint(v); | ||
| + | } | ||
| + | } | ||
| + | </syntaxhighlight> | ||
| + | *The API is the Highcharts object model exposed as Java: <code>Charts</code>, <code>Series</code>, <code>Point</code>, <code>PlotOptions</code>, axes, <code>Tooltip</code>, <code>Marker</code>, per-point <code>Accessibility</code>. See the [https://www.zkoss.org/product/zkcharts ZK Charts product page] and its [https://www.zkoss.org/zkchartsdemo/ live demo gallery] for the full component set. | ||
| + | *The <code>org.idempiere.zkcharts.dashboard</code> bundle carries a minimal working example of exactly this. Its menu entry ships '''deactivated''' because the dashboard supersedes it; reactivate the <code>AD_Menu</code> and <code>AD_Form</code> records named "ZK Charts Example" to open it in the UI. | ||
| + | |||
| + | ==Verifying== | ||
| + | |||
| + | ===Verifying the renderer=== | ||
| + | *The renderer has no menu entry, so it is verified by opening things iDempiere already draws. | ||
| + | *#'''Felix Console → Components''': <code>...renderer.ChartRendererServiceImpl</code> must be ''satisfied/active''. A bundle showing ''Active'' does not by itself mean the service registered. | ||
| + | *#Open the '''Chart''' window and pick any chart definition. The preview should show hover tooltips, an entry animation and an export menu. | ||
| + | *#The decisive test: ''Stop'' the renderer bundle in the Felix Console and reload the record – the chart falls back to billboard. ''Start'' it again and reload – ZK Charts is back. | ||
| + | *#Click a bar or a slice; it must still zoom to the underlying records. | ||
| + | *#Open a '''Performance Goal''' record to cover the goal graph and the gauge indicator. | ||
| + | *#Any <code>Failed to render ... with ZK Charts</code> warning in the log means that path silently fell back to billboard. | ||
| + | |||
| + | ===Creating test data=== | ||
| + | *The charts read <code>C_Order</code> and <code>C_OrderLine</code> only – no shipment, invoice or accounting document is required. | ||
| + | *Create a '''Business Partner''': ''Search Key'', ''Name'', a '''Business Partner Group''' (mandatory, with no default), and tick '''Customer'''. Add a row on the '''Location''' tab, otherwise an order cannot be raised. | ||
| + | *Create a '''Sales Order''' with the document type '''Standard Order''', add lines with products that carry a price, then press '''Complete'''. | ||
| + | *Use ''Standard Order'' deliberately: unlike ''POS Order'' and ''On Credit Order'' it does not auto-generate an invoice on completion, which keeps the accounting setup out of the picture entirely. | ||
| + | |||
| + | ==Troubleshooting== | ||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Symptom !! Cause !! Fix |
| + | |- | ||
| + | | Every chart empty, KPIs all zero || Signed in to the System client, which holds no business data || Log in to GardenWorld or another client with data | ||
|- | |- | ||
| − | | | + | | Bundle stays ''Resolved'', never ''Active'' || The fragment is missing, or the runtime was not restarted after installing it || Install the fragment, then restart |
|- | |- | ||
| − | | | + | | Charts still look unchanged after installing the renderer || The declarative service did not register || Check '''Components''', not just '''Bundles''' |
|- | |- | ||
| − | | <code> | + | | Completing an order fails with ''No account defined for this organization / currency'' || Despite the wording this is a '''bank''' account: the payment rule is ''Cash'' and the document type auto-creates an invoice, but no <code>C_BankAccount</code> matches the order's organisation and currency || Use ''Standard Order'' with payment rule ''On Credit'', or create a bank account in the '''same organisation''' – the lookup matches <code>AD_Org_ID</code> exactly, so one on <code>*</code> will not do |
|} | |} | ||
| − | + | ==How it works== | |
| − | |||
| − | |||
| − | == | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
===Rendering every iDempiere chart with ZK Charts=== | ===Rendering every iDempiere chart with ZK Charts=== | ||
| Line 77: | Line 188: | ||
| <code>WChartEditor</code> || Chart fields inside a window | | <code>WChartEditor</code> || Chart fields inside a window | ||
|} | |} | ||
| − | *The data loading is deliberately identical to the core billboard renderer, so existing <code>AD_Chart</code> definitions keep producing exactly the same numbers – only the widget is swapped | + | *The data loading is deliberately identical to the core billboard renderer, so existing <code>AD_Chart</code> definitions keep producing exactly the same numbers – only the widget is swapped. |
| − | |||
====Chart type mapping==== | ====Chart type mapping==== | ||
| Line 105: | Line 215: | ||
*Menu: '''ZK Charts Live Sales Dashboard''' | *Menu: '''ZK Charts Live Sales Dashboard''' | ||
*Four KPI tiles and three charts – sales by month, top products by sales, and top products on hand. Nothing has to be refreshed by hand: | *Four KPI tiles and three charts – sales by month, top products by sales, and top products on hand. Nothing has to be refreshed by hand: | ||
| − | *#An OSGi <code>EventHandler</code> subscribes to <code>PO_POST_CREATE</code>, <code>PO_POST_UPADTE</code> and <code>PO_POST_DELETE</code>, filtered to <code>C_Order</code>, <code>C_OrderLine</code>, <code>M_InOut</code> and <code>M_InOutLine</code>. These ''post'' topics fire '''after the transaction commits''', so the reload never reads uncommitted rows. | + | *#An OSGi <code>EventHandler</code> subscribes to <code>PO_POST_CREATE</code>, <code>PO_POST_UPADTE</code> ''(sic – the typo is in iDempiere core)'' and <code>PO_POST_DELETE</code>, filtered to <code>C_Order</code>, <code>C_OrderLine</code>, <code>M_InOut</code> and <code>M_InOutLine</code>. These ''post'' topics fire '''after the transaction commits''', so the reload never reads uncommitted rows. |
*#The handler runs on whichever thread saved the record, so it does nothing beyond <code>Executions.schedule(...)</code>, which hands the reload to the desktop's event thread. | *#The handler runs on whichever thread saved the record, so it does nothing beyond <code>Executions.schedule(...)</code>, which hands the reload to the desktop's event thread. | ||
*#ZK server push sends the new data to the browser. | *#ZK server push sends the new data to the browser. | ||
| Line 111: | Line 221: | ||
**'''Coalescing.''' Completing one order fires a burst of events; an <code>AtomicBoolean</code> collapses them into a single reload. | **'''Coalescing.''' Completing one order fires a burst of events; an <code>AtomicBoolean</code> collapses them into a single reload. | ||
**'''Unregistering.''' The handler is removed in <code>onPageDetached</code>, otherwise every tab a user ever opened would keep a live subscription for the lifetime of the runtime. | **'''Unregistering.''' The handler is removed in <code>onPageDetached</code>, otherwise every tab a user ever opened would keep a live subscription for the lifetime of the runtime. | ||
| − | |||
| − | == | + | ==Components== |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
{| class="wikitable" | {| class="wikitable" | ||
| − | ! | + | ! Bundle !! Kind !! Purpose |
|- | |- | ||
| − | | | + | | <code>org.idempiere.zkcharts.fragment</code> || OSGi fragment || Attaches ZK Charts to the class loader of <code>org.adempiere.ui.zk</code>. '''Required by both plugins below.''' |
|- | |- | ||
| − | | | + | | <code>org.idempiere.zkcharts.renderer</code> || Plugin || The global chart renderer. |
|- | |- | ||
| − | | | + | | <code>org.idempiere.zkcharts.dashboard</code> || Plugin || The live sales dashboard, plus a minimal <code><charts></code> ZUL sample. |
| − | |||
| − | |||
|} | |} | ||
| + | |||
| + | *The two plugins are independent – install either on its own, or both. Both need the ZK Charts fragment. | ||
| + | *The same repository also contains [[Plugin: ZK Pivottable Components]], which is documented separately. | ||
| + | |||
| + | ===Why a fragment is needed=== | ||
| + | *ZK discovers its components through <code>metainfo/zk/lang-addon.xml</code>, which is loaded with the class loader of the bundle ZK runs in – in iDempiere that is <code>org.adempiere.ui.zk</code>. | ||
| + | *OSGi bundles have isolated class loaders, and a '''fragment''' is the only standard way to add resources to another bundle's class loader without modifying it. | ||
| + | *That is why the ZK Charts jar is delivered as a fragment of <code>org.adempiere.ui.zk</code> rather than embedded in the plugins. | ||
| + | |||
| + | ==Licensing== | ||
| + | *'''The plugin source''' is GPLv2 or later and contains '''no ZK binaries'''. Nothing in the iDempiere repository is modified. | ||
| + | *'''ZK Charts is a commercial product''' and is not covered by the plugin's open-source licence. The build pulls it from ZK's '''Evaluation''' repository, so everything on this page can be tried at no cost; a valid licence must be obtained separately before production use. | ||
| + | *'''No lock-in.''' Uninstalling the bundle silently restores iDempiere's core chart rendering – the application dictionary was never touched, so there is nothing to migrate back. Evaluating this plugin is a reversible decision. | ||
| + | *'''To obtain a licence or ask about terms''', contact the ZK Framework team at [email protected] or see the [https://www.zkoss.org/product/zkcharts ZK Charts product page]. | ||
| + | <!-- TODO (page owner): state explicitly what the Evaluation build limits (expiry? watermark? feature gating?) and the licensing model (per developer / per production server). Readers currently have to ask by email to find out. --> | ||
| + | <!-- TODO (page owner): add a maintenance commitment next to Creator/SPONSOR - which branches are supported, and how soon a fragment build follows an iDempiere release. --> | ||
==Building from source== | ==Building from source== | ||
| Line 182: | Line 270: | ||
==See also== | ==See also== | ||
| − | *[[Plugin: ZK Pivottable Components]] | + | *Other ZK plugins for iDempiere: |
| − | *[[Developing Plug-Ins - Get your Plug-In running]] | + | **[[Plugin: ZK Pivottable Components]] |
| − | *[[Make Zk WebApp OSGi]] | + | **[[Plugin: ZK Enterprise Components]] |
| − | *[https://www.zkoss.org/product/zkcharts ZK Charts] | + | **[[Plugin: Keikai Spreadsheet Enterprise Component]] |
| + | *Other charting plugins in this category: | ||
| + | **[[Plugin: Billboard.js Chart]] | ||
| + | **[[Plugin: Chart Maker]] | ||
| + | *Plugin development: | ||
| + | **[[Developing Plug-Ins - Get your Plug-In running]] | ||
| + | **[[Make Zk WebApp OSGi]] | ||
| + | *[https://www.zkoss.org/product/zkcharts ZK Charts] · [https://www.zkoss.org/zkchartsdemo/ ZK Charts demo gallery] | ||
[[Category:Available Plugins]] | [[Category:Available Plugins]] | ||
Revision as of 12:01, 17 August 2026
- Creator: James Chu
- SPONSOR: zkoss.org
- License: The plugin source code is licensed under the GNU GPLv2 or later and contains no ZK binaries. See Licensing for what that means in practice.
- Source: GitHub repository
- Supported branches:
mainfor iDempiere 13,v12for iDempiere 12. - Related: Plugin: ZK Pivottable Components – lives in the same repository and builds on this one.
Description
- This plugin enables iDempiere implementors to use ZK Charts components in iDempiere without modifying iDempiere core. It is designed as an optional add-on: you can install and uninstall it as a standard iDempiere OSGi plugin.
- It covers two ways of using ZK Charts:
- Globally – replace the chart rendering iDempiere already does, so that every existing dashboard chart, performance goal and chart field is drawn with ZK Charts, without changing a single application dictionary record.
- In a dashboard – a sales and inventory dashboard that redraws itself through ZK server push whenever an order or shipment is saved.
- Nothing is one-way. Uninstalling the bundle silently restores the core rendering, and any exception during rendering makes the service return
falseso that iDempiere falls through to the next renderer rather than showing an empty panel.
Why ZK Charts rather than the renderer already in core
- iDempiere 13 ships billboard.js in core at no cost, and it is a perfectly capable client-side chart library. The honest comparison is narrower than "static images versus interactive charts" – that difference is against JFreeChart, which is deprecated in v13.
| JFreeChart (deprecated in v13) | billboard.js (v13 default) | ZK Charts | |
|---|---|---|---|
| Rendering | server-side PNG image | client-side SVG | client-side SVG |
| Interactive tooltips | – | yes | yes |
| Legend toggling | – | yes | yes |
| Entry animation | – | yes | yes |
| Export the chart as PNG / SVG / PDF / CSV | – | – | built in, from the chart's own context menu |
| Click-to-zoom to the underlying records | yes | yes | yes |
AD_Chart chart types covered |
all | all | all |
| Java API available to your own plugin | the JFreeChart API | the Billboard component: title, type, orientation, legend, axis labels, series colours, time series |
the full org.zkoss.chart model – plot options, per-point markers and styling, multiple axes, chart-level events, accessibility descriptions
|
| Accessibility descriptions per point/series | – | – | yes |
| Support | community | community | commercial, under the ZK Charts licence |
| Cost | free | free | commercial licence, evaluation available |
- If all you need is a readable chart on a dashboard, billboard.js already does that. The two reasons to add this plugin are export straight from the chart and the much larger API surface when you build charts in your own forms – plus commercial support on the component itself.
Requirements
| Item | Version |
|---|---|
| iDempiere | 13 (use the v12 branch for iDempiere 12)
|
| Java runtime | 17 |
| ZK CE bundled with iDempiere | 10.0.1 |
| ZK Charts | 12.5.0.0-Eval |
Installation
- Obtain the three jars – see Building from source.
- The order matters – a fragment only takes effect after its host bundle is re-resolved, which means a restart:
- Install
org.idempiere.zkcharts.fragmentthrough the Felix Web Console (/osgi/system/console/bundles). - Restart the iDempiere runtime.
- Install
org.idempiere.zkcharts.rendererand/ororg.idempiere.zkcharts.dashboard. - On the Bundles page, confirm the fragment shows as Fragment and the plugins as Active – not merely Resolved.
- Log out and back in, so the menu tree is rebuilt with the entries the plugin adds.
- Install
- The dashboard plugin adds its menu entries through a 2Pack applied by its bundle activator; no manual import is required.
Usage
The client you log in as matters
- Every chart is scoped to the logged in client, and most of them to completed sales orders.
SuperUsersigns in to the System client (AD_Client_ID = 0), which by design holds the dictionary and no business data at all – so every chart is legitimately empty and nothing is broken.- Log in as
GardenAdminto the GardenWorld client instead.
Using ZK Charts in your own plugin
- This is the part most plugin developers come for. There are three pieces, and the third one is the rule that follows from the fragment design.
- 1. Compile-time dependency. Add the ZK Evaluation repository and the ZK Charts jar to your bundle's
pom.xml. Tycho copies it onto the compile classpath; it is not embedded in your jar.
<repositories>
<repository>
<id>ZK PE/EE Evaluation</id>
<url>https://mavensync.zkoss.org/eval/</url>
</repository>
</repositories>
<dependencies>
<!-- Compile time only: at runtime the classes come from
org.idempiere.zkcharts.fragment through org.adempiere.ui.zk -->
<dependency>
<groupId>org.zkoss.chart</groupId>
<artifactId>zkcharts</artifactId>
<version>12.5.0.0-Eval</version>
</dependency>
</dependencies>
- 2. Runtime wiring in
META-INF/MANIFEST.MF. You do not importorg.zkoss.chartdirectly. The fragment exports those packages through its host, so requiring the host bundle is what makes them visible:
Require-Bundle: org.adempiere.base;bundle-version="13.0.0",
org.adempiere.ui.zk;bundle-version="13.0.0",
zk;bundle-version="10.0.1",
zul;bundle-version="10.0.1"
- 3. The rule. You compile against a jar on the Maven classpath but resolve at runtime through the fragment – so your bundle will not resolve unless
org.idempiere.zkcharts.fragmentis installed and the runtime has been restarted since. A bundle stuck at Resolved or Installed is almost always this. - A working ZUL.
<charts>is a normal ZK component once the fragment is in place:
<?xml version="1.0" encoding="UTF-8"?>
<zk>
<window apply="org.example.myplugin.MyChartComposer">
<charts id="chart" type="spline" title="Monthly Average Temperature"/>
</window>
</zk>
public class MyChartComposer extends SelectorComposer<Component> {
@Wire private Charts chart;
@Override
public void doAfterCompose(Component comp) throws Exception {
super.doAfterCompose(comp);
chart.getYAxis().getTitle().setText("Temperature (°C)");
chart.getTooltip().setShared(true);
Series tokyo = chart.getSeries();
tokyo.setName("Tokyo");
tokyo.getMarker().setSymbol("square");
for (double v : new double[] {5.2, 5.7, 8.7, 13.9, 18.2, 21.4, 25.0})
tokyo.addPoint(v);
}
}
- The API is the Highcharts object model exposed as Java:
Charts,Series,Point,PlotOptions, axes,Tooltip,Marker, per-pointAccessibility. See the ZK Charts product page and its live demo gallery for the full component set. - The
org.idempiere.zkcharts.dashboardbundle carries a minimal working example of exactly this. Its menu entry ships deactivated because the dashboard supersedes it; reactivate theAD_MenuandAD_Formrecords named "ZK Charts Example" to open it in the UI.
Verifying
Verifying the renderer
- The renderer has no menu entry, so it is verified by opening things iDempiere already draws.
- Felix Console → Components:
...renderer.ChartRendererServiceImplmust be satisfied/active. A bundle showing Active does not by itself mean the service registered. - Open the Chart window and pick any chart definition. The preview should show hover tooltips, an entry animation and an export menu.
- The decisive test: Stop the renderer bundle in the Felix Console and reload the record – the chart falls back to billboard. Start it again and reload – ZK Charts is back.
- Click a bar or a slice; it must still zoom to the underlying records.
- Open a Performance Goal record to cover the goal graph and the gauge indicator.
- Any
Failed to render ... with ZK Chartswarning in the log means that path silently fell back to billboard.
- Felix Console → Components:
Creating test data
- The charts read
C_OrderandC_OrderLineonly – no shipment, invoice or accounting document is required. - Create a Business Partner: Search Key, Name, a Business Partner Group (mandatory, with no default), and tick Customer. Add a row on the Location tab, otherwise an order cannot be raised.
- Create a Sales Order with the document type Standard Order, add lines with products that carry a price, then press Complete.
- Use Standard Order deliberately: unlike POS Order and On Credit Order it does not auto-generate an invoice on completion, which keeps the accounting setup out of the picture entirely.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| Every chart empty, KPIs all zero | Signed in to the System client, which holds no business data | Log in to GardenWorld or another client with data |
| Bundle stays Resolved, never Active | The fragment is missing, or the runtime was not restarted after installing it | Install the fragment, then restart |
| Charts still look unchanged after installing the renderer | The declarative service did not register | Check Components, not just Bundles |
| Completing an order fails with No account defined for this organization / currency | Despite the wording this is a bank account: the payment rule is Cash and the document type auto-creates an invoice, but no C_BankAccount matches the order's organisation and currency |
Use Standard Order with payment rule On Credit, or create a bank account in the same organisation – the lookup matches AD_Org_ID exactly, so one on * will not do
|
How it works
Rendering every iDempiere chart with ZK Charts
org.idempiere.zkcharts.rendererneeds no configuration and adds no menu entry. It registers an implementation of the OSGi serviceIChartRendererServicewith a higher service ranking than the ones in core, and iDempiere then asks it first.
| Implementation | service.ranking
|
|---|---|
org.idempiere.zkcharts.renderer (this plugin) |
100 |
org.idempiere.zk.billboard.chart (billboard.js, the v13 default) |
0 |
org.adempiere.webui.apps.graph.jfreegraph (JFreeChart, deprecated since v13) |
-1 |
- Everything that draws a chart in the web UI goes through that service, so all of the following change at once:
| Consumer | What it draws |
|---|---|
DashboardController |
PA_DashboardContent chart gadgets
|
WGraph |
PA_Goal performance graphs
|
WPerformanceIndicator |
PA_Goal performance indicators, drawn as a gauge
|
WChartEditor |
Chart fields inside a window |
- The data loading is deliberately identical to the core billboard renderer, so existing
AD_Chartdefinitions keep producing exactly the same numbers – only the widget is swapped.
Chart type mapping
AD_Chart.ChartType |
ZK Charts |
|---|---|
| Bar / 3D Bar | column, or bar when Chart Orientation is Horizontal
|
| Stacked Bar / 3D Stacked Bar | the same, with stacking: normal
|
| Line / 3D Line | line
|
| Area | area
|
| Stacked Area | area with stacking: normal
|
| Pie / 3D Pie | pie
|
| Ring | pie with innerSize: 60%
|
| Waterfall | waterfall, running totals converted to per-step deltas
|
- 3D variants render as their 2D counterpart, which is also what the core billboard renderer does.
PA_Goalindicators render as agaugewhose plot bands come from the goal's colour schema.
Live sales and inventory dashboard
- Menu: ZK Charts Live Sales Dashboard
- Four KPI tiles and three charts – sales by month, top products by sales, and top products on hand. Nothing has to be refreshed by hand:
- An OSGi
EventHandlersubscribes toPO_POST_CREATE,PO_POST_UPADTE(sic – the typo is in iDempiere core) andPO_POST_DELETE, filtered toC_Order,C_OrderLine,M_InOutandM_InOutLine. These post topics fire after the transaction commits, so the reload never reads uncommitted rows. - The handler runs on whichever thread saved the record, so it does nothing beyond
Executions.schedule(...), which hands the reload to the desktop's event thread. - ZK server push sends the new data to the browser.
- An OSGi
- Two details worth copying into your own plugin:
- Coalescing. Completing one order fires a burst of events; an
AtomicBooleancollapses them into a single reload. - Unregistering. The handler is removed in
onPageDetached, otherwise every tab a user ever opened would keep a live subscription for the lifetime of the runtime.
- Coalescing. Completing one order fires a burst of events; an
Components
| Bundle | Kind | Purpose |
|---|---|---|
org.idempiere.zkcharts.fragment |
OSGi fragment | Attaches ZK Charts to the class loader of org.adempiere.ui.zk. Required by both plugins below.
|
org.idempiere.zkcharts.renderer |
Plugin | The global chart renderer. |
org.idempiere.zkcharts.dashboard |
Plugin | The live sales dashboard, plus a minimal <charts> ZUL sample.
|
- The two plugins are independent – install either on its own, or both. Both need the ZK Charts fragment.
- The same repository also contains Plugin: ZK Pivottable Components, which is documented separately.
Why a fragment is needed
- ZK discovers its components through
metainfo/zk/lang-addon.xml, which is loaded with the class loader of the bundle ZK runs in – in iDempiere that isorg.adempiere.ui.zk. - OSGi bundles have isolated class loaders, and a fragment is the only standard way to add resources to another bundle's class loader without modifying it.
- That is why the ZK Charts jar is delivered as a fragment of
org.adempiere.ui.zkrather than embedded in the plugins.
Licensing
- The plugin source is GPLv2 or later and contains no ZK binaries. Nothing in the iDempiere repository is modified.
- ZK Charts is a commercial product and is not covered by the plugin's open-source licence. The build pulls it from ZK's Evaluation repository, so everything on this page can be tried at no cost; a valid licence must be obtained separately before production use.
- No lock-in. Uninstalling the bundle silently restores iDempiere's core chart rendering – the application dictionary was never touched, so there is nothing to migrate back. Evaluating this plugin is a reversible decision.
- To obtain a licence or ask about terms, contact the ZK Framework team at [email protected] or see the ZK Charts product page.
Building from source
- Requires Git, Maven, JDK 17 and a local p2 repository built from iDempiere core. Full instructions, including the target platform fix-ups, are in the repository README.
git clone --branch release-13 https://github.com/idempiere/idempiere.git idempiere
cd idempiere && mvn clean install
git clone https://github.com/zkoss-demo/zkoss-idempiere-addon-plugin.git
cd zkoss-idempiere-addon-plugin
(cd org.idempiere.zkcharts.fragment && mvn clean verify)
(cd org.idempiere.zkcharts.renderer && mvn clean verify)
(cd org.idempiere.zkcharts.dashboard && mvn clean verify)
- The first build must have network access: ZK Charts is downloaded from the ZK Evaluation repository, not from Maven Central.
Feedback
- If you would like to discuss specific use cases or workflows for this plugin, we’d be happy to hear from you. Please feel free to contact the ZK Framework team at [email protected].
- If you want to provide additional comments, please use:
- General support forum: iDempiere Community
- Issues for this plugin: GitHub Issues
See also
- Other ZK plugins for iDempiere:
- Other charting plugins in this category:
- Plugin development:
- ZK Charts · ZK Charts demo gallery
