IDEMPIERE-5609 Dashboard Performance Indicators incrementally redrawed on DC drag and drop (#1736)

This commit is contained in:
hengsin 2023-03-17 18:45:56 +08:00 committed by GitHub
parent efcd7352f2
commit e479eb5cfb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 111 additions and 54 deletions

View File

@ -198,6 +198,8 @@ public class MSysConfig extends X_AD_SysConfig
public static final String ZK_BUTTON_STYLE = "ZK_BUTTON_STYLE";
public static final String ZK_DASHBOARD_CALENDAR_REQUEST_DISPLAY_MODE = "ZK_DASHBOARD_CALENDAR_REQUEST_DISPLAY_MODE";
public static final String ZK_DASHBOARD_PERFORMANCE_REFRESH_INTERVAL = "ZK_DASHBOARD_PERFORMANCE_REFRESH_INTERVAL";
/** @deprecated not use for the new billboard implementation */
@Deprecated(forRemoval = true, since = "11")
public static final String ZK_DASHBOARD_PERFORMANCE_TIMEOUT = "ZK_DASHBOARD_PERFORMANCE_TIMEOUT";
public static final String ZK_DASHBOARD_REFRESH_INTERVAL = "ZK_DASHBOARD_REFRESH_INTERVAL";
public static final String ZK_DECIMALBOX_PROCESS_DOTKEYPAD = "ZK_DECIMALBOX_PROCESS_DOTKEYPAD";

View File

@ -1,5 +1,36 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
* - carlos *
* - elaine *
* - hieplq *
**********************************************************************/
package org.adempiere.webui.apps.graph;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import org.adempiere.webui.apps.graph.WPerformanceIndicator.Options;
import org.adempiere.webui.component.Grid;
import org.adempiere.webui.component.Panel;
@ -16,15 +47,14 @@ import org.zkoss.zul.Label;
public class WPAPanel extends Panel implements EventListener<Event>
{
/**
*
* generated serial id
*/
private static final long serialVersionUID = -6367672112341229048L;
/**
* Get Panel if User has Performance Goals
* @return panel pr null
* Load Performance Goals for current login user
* @return MGoal[]
*/
public static MGoal[] loadGoal()
{
@ -33,16 +63,23 @@ public class WPAPanel extends Panel implements EventListener<Event>
return goals;
}
/**************************************************************************
* Constructor
/**
* Default Constructor
*/
public WPAPanel ()
{
super ();
}
/**
* Set performance goals and render charts
* @param goals
* @param options color map options
*/
public void setGoals (MGoal[] goals, Options options){
m_goals = goals;
m_goals = goals;
if (getChildren().size() > 0)
getChildren().clear();
init(options);
}
@ -53,7 +90,7 @@ public class WPAPanel extends Panel implements EventListener<Event>
private static final CLogger log = CLogger.getCLogger (WPAPanel.class);
/**
* Static/Dynamic Init
* Layout panel and render charts
* @param options
*/
private void init(Options options)
@ -67,6 +104,7 @@ public class WPAPanel extends Panel implements EventListener<Event>
grid.appendChild(rows);
Row row = null;
List<WPerformanceIndicator> list = new ArrayList<>();
for (int i = 0; i < m_goals.length; i++)
{
if (row == null || i % 2 == 0)
@ -79,6 +117,14 @@ public class WPAPanel extends Panel implements EventListener<Event>
row.appendChild(div);
div.setSclass("performance-indicator-box");
WPerformanceIndicator pi = new WPerformanceIndicator(m_goals[i], options);
list.add(pi);
pi.addEventListener(WPerformanceIndicator.ON_AFTER_RENDER_CHART_EVENT, e -> {
boolean removed = list.remove(e.getTarget());
if (removed && list.isEmpty()) {
//notify all chart have been rendered
Events.sendEvent(WPAPanel.this, new Event(WPerformanceIndicator.ON_AFTER_RENDER_CHART_EVENT));
}
});
div.appendChild(pi);
pi.addEventListener(Events.ON_CLICK, this);
Div titleDiv = new Div();
@ -90,15 +136,17 @@ public class WPAPanel extends Panel implements EventListener<Event>
} // init
/**
* Action Listener for Drill Down
* Event Listener for Drill Down
* @param e event
*/
@Override
public void onEvent(Event e) throws Exception
{
if (e.getTarget() instanceof WPerformanceIndicator)
{
WPerformanceIndicator pi = (WPerformanceIndicator) e.getTarget();
log.info(pi.toString());
if (log.isLoggable(Level.INFO))
log.info(pi.toString());
MGoal goal = pi.getGoal();
if (goal.getMeasure() != null)
new WPerformanceDetail(goal);

View File

@ -42,23 +42,29 @@ import org.zkoss.zul.Menupopup;
*/
public class WPerformanceIndicator extends Panel implements EventListener<Event>
{
/**
* generated serial id
*/
private static final long serialVersionUID = 4102528939759426552L;
/** Event after chart have been rendered */
public static final String ON_AFTER_RENDER_CHART_EVENT = "onAfterRenderChart";
public static final String TICK_COLOR = "tickColor";
public static final String NEEDLE_COLOR = "needleColor";
public static final String DIAL_BACKGROUND = "dialBackground";
public static final String CHART_BACKGROUND = "chartBackground";
/**
*
* @param goal
*/
private static final long serialVersionUID = 3580494126343850939L;
public WPerformanceIndicator(MGoal goal)
{
this(goal, null);
}
/**
* Constructor
* @param goal goal model
* @param goal goal model
* @param options
*/
public WPerformanceIndicator(MGoal goal, Options options)
{
@ -99,7 +105,7 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
/** Integer Number Format */
private static DecimalFormat s_format = DisplayType.getNumberFormat(DisplayType.Integer);
Menupopup popupMenu = new Menupopup();
protected Menupopup popupMenu = new Menupopup();
private Menuitem mRefresh = new Menuitem(Msg.getMsg(Env.getCtx(), "Refresh"), ThemeManager.getThemeResource("images/Refresh16.png"));
private Color chartBackground = new Color(0.0f, 0.0f, 0.0f, 0.0f);
@ -107,7 +113,7 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
private Color needleColor = Color.darkGray;
private Color tickColor = Color.darkGray;
ChartPanel chartPanel;
protected ChartPanel chartPanel;
/**
* Get Goal
@ -119,7 +125,7 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
} // getGoal
/**
* Init Graph Display
* Initialization
* Kinamo (pelgrim)
*/
private void init()
@ -142,10 +148,12 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
text.append(" ").append(Msg.getMsg(Env.getCtx(), "of")).append(" ")
.append(s_format.format(m_goal.getMeasureTarget()));
setTooltiptext(text.toString());
//chart render in after size event
addEventListener(Events.ON_AFTER_SIZE, this);
}
@Override
public void onEvent(Event event) throws Exception
{
if (Events.ON_AFTER_SIZE.equals(event.getName()))
@ -159,6 +167,10 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
}
}
/**
* Handle after size event. Call {@link #renderChart(int, int)}
* @param event
*/
private void onAfterSize(AfterSizeEvent event) {
int width = event.getWidth();
if (width == 0)
@ -183,14 +195,23 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
}
}
this.getChildren().clear();
renderChart(width, height);
renderChart(width, height);
Events.sendEvent(this, new Event(ON_AFTER_RENDER_CHART_EVENT));
}
/**
* @return title
*/
public String getTitle()
{
return m_text;
}
/**
* render chart
* @param chartWidth
* @param chartHeight
*/
private void renderChart(int chartWidth, int chartHeight)
{
IndicatorModel model = new IndicatorModel();
@ -207,6 +228,9 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
this.getFirstChild().addEventListener(Events.ON_CLICK, this);
}
/**
* Class for color map options
*/
public static class Options {
public Map<String, Color> colorMap;
}

View File

@ -14,16 +14,13 @@
package org.adempiere.webui.dashboard;
import org.adempiere.webui.apps.graph.WPAPanel;
import org.adempiere.webui.apps.graph.WPerformanceIndicator;
import org.adempiere.webui.apps.graph.WPerformanceIndicator.Options;
import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.MGoal;
import org.compiere.model.MSysConfig;
import org.compiere.util.Env;
import org.zkoss.zk.au.out.AuScript;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.util.Clients;
/**
@ -31,66 +28,52 @@ import org.zkoss.zk.ui.util.Clients;
* @author Elaine
* @date November 20, 2008
*/
public class DPPerformance extends DashboardPanel {
private static final String ON_POST_RENDER_ATTR = "onPostRender.Event.Posted";
public class DPPerformance extends DashboardPanel {
/**
*
* generated serial id
*/
private static final long serialVersionUID = -8878665031716441912L;
/** performance chart panel */
private WPAPanel paPanel;
private MGoal[] performanceData;
/**
* Default constructor
*/
public DPPerformance()
{
super();
setSclass("performance-widget");
// have to add at least a child component, other it will be remove from DashboardController
// and can't update when finish load data
paPanel = new WPAPanel();
appendChild(paPanel);
paPanel.addEventListener(WPerformanceIndicator.ON_AFTER_RENDER_CHART_EVENT, e -> onPostRender());
}
@Override
public void refresh(ServerPushTemplate template) {
performanceData = WPAPanel.loadGoal();
performanceData = WPAPanel.loadGoal();
//usually, this should be call in non UI/Event listener thread (i.e Executions.getCurrent() should be null)
if (Executions.getCurrent() != null) {
updateUI();
if (this.getAttribute(ON_POST_RENDER_ATTR) == null && paPanel.getChildren().size() > 0) {
setAttribute(ON_POST_RENDER_ATTR, Boolean.TRUE);
Events.echoEvent("onPostRender", this, null);
}
updateUI();
} else {
template.executeAsync(this);
}
}
@Override
public void onPageAttached(Page newpage, Page oldpage) {
super.onPageAttached(newpage, oldpage);
if (newpage != null) {
if (Executions.getCurrent() != null) {
if (this.getAttribute(ON_POST_RENDER_ATTR) == null && paPanel.getChildren().size() > 0) {
setAttribute(ON_POST_RENDER_ATTR, Boolean.TRUE);
Events.echoEvent("onPostRender", this, null);
}
}
}
}
//adjust window height to match grid height
/**
* Adjust {@link #paPanel} height to match chart/content height
*/
public void onPostRender()
{
removeAttribute(ON_POST_RENDER_ATTR);
if (this.getFirstChild() != null)
{
int timeout = MSysConfig.getIntValue(MSysConfig.ZK_DASHBOARD_PERFORMANCE_TIMEOUT, 500, Env.getAD_Client_ID(Env.getCtx()));
//first child of paPanel, the Grid layout
Component grid = this.getFirstChild().getFirstChild();
String script = "setTimeout(function() { let grid = jq('#" + grid.getUuid() + "');";
script = script + "grid.parent().height(grid.css('height'));}, " + timeout + ");";
script = script + "grid.parent().height(grid.css('height'));}, 10);";
if (Executions.getCurrent() != null)
Clients.response(new AuScript(script));
this.getFirstChild().invalidate();
}
}