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:''' This plugin is licensed under the GNU [http://www.gnu.org/licenses/gpl-2.0.html GPLv2] or later. The plugin source code itself does not include ZK Charts.
+
*'''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]
−
*'''Dependencies:''' This plugin depends on ZK Charts, a commercial product that is not covered by this plugin’s open-source license. Users must obtain a valid license separately for production use.
+
*'''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/uninstall it as a standard iDempiere OSGi plugin.
+
*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.
−
*ZK Charts is a commercial product (evaluation is available via ZK download center).
+
*'''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>&lt;charts&gt;</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"
−
! Bundle !! Kind !! Purpose
+
! 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
 
|-
 
|-
−
| <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.'''
+
| Bundle stays ''Resolved'', never ''Active'' || The fragment is missing, or the runtime was not restarted after installing it || Install the fragment, then restart
 
|-
 
|-
−
| <code>org.idempiere.zkcharts.renderer</code> || Plugin || The global chart renderer.
+
| Charts still look unchanged after installing the renderer || The declarative service did not register || Check '''Components''', not just '''Bundles'''
 
|-
 
|-
−
| <code>org.idempiere.zkcharts.dashboard</code> || Plugin || The live sales dashboard, plus a minimal <code>&lt;charts&gt;</code> ZUL sample.
+
| 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
 
|}
 
|}
  
−
*The two plugins are independent – install either on its own, or both. Both need the ZK Charts fragment.
+
==How it works==
−
*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.
 
−
 
 
−
==Features==
 
−
*Integrate ZK Charts libraries into the iDempiere runtime as an optional add-on.
 
−
*Replace iDempiere's built-in chart rendering with ZK Charts, with no application dictionary change.
 
−
*Provide example window/form(s) to verify charts render correctly in iDempiere.
 
−
*Keep iDempiere core unchanged (plugin-based integration).
 
  
 
===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. What you gain is interactive tooltips, legend toggling, animation and the built-in export menu. Click-to-zoom still opens the underlying records.
+
*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.
−
*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.
 
  
 
====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.
−
*This module also carries the smallest possible example of using <code>&lt;charts&gt;</code> in a ZUL. 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 bring it back.
 
  
−
==Installation==
+
==Components==
−
*Download the release / install package from the GitHub repository.
 
−
*Install the OSGi plugin and fragment into your iDempiere runtime (same way as other plugins). '''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==
 
−
*After installation, open the included examples from the iDempiere menu and verify charts render correctly.
 
−
*To use charts in your own windows/forms, add dependencies on this plugin and develop with ZK Charts as usual.
 
−
*Demo builds may include evaluation versions of ZK Charts for demonstration purposes only. A valid commercial license is required for production use.
 
−
 
 
−
===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.
 
−
 
 
−
===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
+
! Bundle !! Kind !! Purpose
 
|-
 
|-
−
| 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
+
| <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.'''
 
|-
 
|-
−
| Bundle stays ''Resolved'', never ''Active'' || The fragment is missing, or the runtime was not restarted after installing it || Install the fragment, then restart
+
| <code>org.idempiere.zkcharts.renderer</code> || Plugin || The global chart renderer.
 
|-
 
|-
−
| Charts still look unchanged after installing the renderer || The declarative service did not register || Check '''Components''', not just '''Bundles'''
+
| <code>org.idempiere.zkcharts.dashboard</code> || Plugin || The live sales dashboard, plus a minimal <code>&lt;charts&gt;</code> ZUL sample.
−
|-
 
−
| 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
 
 
|}
 
|}
 +
 +
*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

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:
    1. 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.
    2. 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 false so that iDempiere falls through to the next renderer rather than showing an empty panel.
An existing AD_Chart rendered with ZK Charts
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.
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:
    1. Install org.idempiere.zkcharts.fragment through the Felix Web Console (/osgi/system/console/bundles).
    2. Restart the iDempiere runtime.
    3. Install org.idempiere.zkcharts.renderer and/or org.idempiere.zkcharts.dashboard.
    4. On the Bundles page, confirm the fragment shows as Fragment and the plugins as Active – not merely Resolved.
    5. 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.
  • SuperUser signs 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 GardenAdmin 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 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 import org.zkoss.chart directly. 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.fragment is 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-point Accessibility. See the ZK Charts product page and its live demo gallery for the full component set.
  • The org.idempiere.zkcharts.dashboard bundle carries a minimal working example of exactly this. Its menu entry ships deactivated because the dashboard supersedes it; reactivate the AD_Menu and AD_Form 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.
    1. Felix Console → Components: ...renderer.ChartRendererServiceImpl must be satisfied/active. A bundle showing Active does not by itself mean the service registered.
    2. Open the Chart window and pick any chart definition. The preview should show hover tooltips, an entry animation and an export menu.
    3. 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.
    4. Click a bar or a slice; it must still zoom to the underlying records.
    5. Open a Performance Goal record to cover the goal graph and the gauge indicator.
    6. Any Failed to render ... with ZK Charts warning in the log means that path silently fell back to billboard.

Creating test data

  • The charts read C_Order and C_OrderLine 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

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.renderer needs no configuration and adds no menu entry. It registers an implementation of the OSGi service IChartRendererService with 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_Chart definitions 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_Goal indicators render as a gauge whose 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:
    1. An OSGi EventHandler subscribes to PO_POST_CREATE, PO_POST_UPADTE (sic – the typo is in iDempiere core) and PO_POST_DELETE, filtered to C_Order, C_OrderLine, M_InOut and M_InOutLine. These post topics fire after the transaction commits, so the reload never reads uncommitted rows.
    2. 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.
    3. ZK server push sends the new data to the browser.
  • Two details worth copying into your own plugin:
    • Coalescing. Completing one order fires a burst of events; an AtomicBoolean collapses 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.

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 is org.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.zk 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 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:

See also

Cookies help us deliver our services. By using our services, you agree to our use of cookies.