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_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_CALENDAR_REQUEST_DISPLAY_MODE = "ZK_DASHBOARD_CALENDAR_REQUEST_DISPLAY_MODE";
public static final String ZK_DASHBOARD_PERFORMANCE_REFRESH_INTERVAL = "ZK_DASHBOARD_PERFORMANCE_REFRESH_INTERVAL"; 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_PERFORMANCE_TIMEOUT = "ZK_DASHBOARD_PERFORMANCE_TIMEOUT";
public static final String ZK_DASHBOARD_REFRESH_INTERVAL = "ZK_DASHBOARD_REFRESH_INTERVAL"; public static final String ZK_DASHBOARD_REFRESH_INTERVAL = "ZK_DASHBOARD_REFRESH_INTERVAL";
public static final String ZK_DECIMALBOX_PROCESS_DOTKEYPAD = "ZK_DECIMALBOX_PROCESS_DOTKEYPAD"; 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; 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.apps.graph.WPerformanceIndicator.Options;
import org.adempiere.webui.component.Grid; import org.adempiere.webui.component.Grid;
import org.adempiere.webui.component.Panel; import org.adempiere.webui.component.Panel;
@ -16,15 +47,14 @@ import org.zkoss.zul.Label;
public class WPAPanel extends Panel implements EventListener<Event> public class WPAPanel extends Panel implements EventListener<Event>
{ {
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = -6367672112341229048L; private static final long serialVersionUID = -6367672112341229048L;
/** /**
* Get Panel if User has Performance Goals * Load Performance Goals for current login user
* @return panel pr null * @return MGoal[]
*/ */
public static MGoal[] loadGoal() public static MGoal[] loadGoal()
{ {
@ -33,16 +63,23 @@ public class WPAPanel extends Panel implements EventListener<Event>
return goals; return goals;
} }
/************************************************************************** /**
* Constructor * Default Constructor
*/ */
public WPAPanel () public WPAPanel ()
{ {
super (); super ();
} }
/**
* Set performance goals and render charts
* @param goals
* @param options color map options
*/
public void setGoals (MGoal[] goals, Options options){ public void setGoals (MGoal[] goals, Options options){
m_goals = goals; m_goals = goals;
if (getChildren().size() > 0)
getChildren().clear();
init(options); init(options);
} }
@ -53,7 +90,7 @@ public class WPAPanel extends Panel implements EventListener<Event>
private static final CLogger log = CLogger.getCLogger (WPAPanel.class); private static final CLogger log = CLogger.getCLogger (WPAPanel.class);
/** /**
* Static/Dynamic Init * Layout panel and render charts
* @param options * @param options
*/ */
private void init(Options options) private void init(Options options)
@ -67,6 +104,7 @@ public class WPAPanel extends Panel implements EventListener<Event>
grid.appendChild(rows); grid.appendChild(rows);
Row row = null; Row row = null;
List<WPerformanceIndicator> list = new ArrayList<>();
for (int i = 0; i < m_goals.length; i++) for (int i = 0; i < m_goals.length; i++)
{ {
if (row == null || i % 2 == 0) if (row == null || i % 2 == 0)
@ -79,6 +117,14 @@ public class WPAPanel extends Panel implements EventListener<Event>
row.appendChild(div); row.appendChild(div);
div.setSclass("performance-indicator-box"); div.setSclass("performance-indicator-box");
WPerformanceIndicator pi = new WPerformanceIndicator(m_goals[i], options); 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); div.appendChild(pi);
pi.addEventListener(Events.ON_CLICK, this); pi.addEventListener(Events.ON_CLICK, this);
Div titleDiv = new Div(); Div titleDiv = new Div();
@ -90,15 +136,17 @@ public class WPAPanel extends Panel implements EventListener<Event>
} // init } // init
/** /**
* Action Listener for Drill Down * Event Listener for Drill Down
* @param e event * @param e event
*/ */
@Override
public void onEvent(Event e) throws Exception public void onEvent(Event e) throws Exception
{ {
if (e.getTarget() instanceof WPerformanceIndicator) if (e.getTarget() instanceof WPerformanceIndicator)
{ {
WPerformanceIndicator pi = (WPerformanceIndicator) e.getTarget(); WPerformanceIndicator pi = (WPerformanceIndicator) e.getTarget();
log.info(pi.toString()); if (log.isLoggable(Level.INFO))
log.info(pi.toString());
MGoal goal = pi.getGoal(); MGoal goal = pi.getGoal();
if (goal.getMeasure() != null) if (goal.getMeasure() != null)
new WPerformanceDetail(goal); new WPerformanceDetail(goal);

View File

@ -42,23 +42,29 @@ import org.zkoss.zul.Menupopup;
*/ */
public class WPerformanceIndicator extends Panel implements EventListener<Event> 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 TICK_COLOR = "tickColor";
public static final String NEEDLE_COLOR = "needleColor"; public static final String NEEDLE_COLOR = "needleColor";
public static final String DIAL_BACKGROUND = "dialBackground"; public static final String DIAL_BACKGROUND = "dialBackground";
public static final String CHART_BACKGROUND = "chartBackground"; public static final String CHART_BACKGROUND = "chartBackground";
/**
*
*/
private static final long serialVersionUID = 3580494126343850939L;
/**
* @param goal
*/
public WPerformanceIndicator(MGoal goal) public WPerformanceIndicator(MGoal goal)
{ {
this(goal, null); this(goal, null);
} }
/** /**
* Constructor * @param goal goal model
* @param goal goal model * @param options
*/ */
public WPerformanceIndicator(MGoal goal, Options options) public WPerformanceIndicator(MGoal goal, Options options)
{ {
@ -99,7 +105,7 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
/** Integer Number Format */ /** Integer Number Format */
private static DecimalFormat s_format = DisplayType.getNumberFormat(DisplayType.Integer); 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 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); 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 needleColor = Color.darkGray;
private Color tickColor = Color.darkGray; private Color tickColor = Color.darkGray;
ChartPanel chartPanel; protected ChartPanel chartPanel;
/** /**
* Get Goal * Get Goal
@ -119,7 +125,7 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
} // getGoal } // getGoal
/** /**
* Init Graph Display * Initialization
* Kinamo (pelgrim) * Kinamo (pelgrim)
*/ */
private void init() private void init()
@ -143,9 +149,11 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
.append(s_format.format(m_goal.getMeasureTarget())); .append(s_format.format(m_goal.getMeasureTarget()));
setTooltiptext(text.toString()); setTooltiptext(text.toString());
//chart render in after size event
addEventListener(Events.ON_AFTER_SIZE, this); addEventListener(Events.ON_AFTER_SIZE, this);
} }
@Override
public void onEvent(Event event) throws Exception public void onEvent(Event event) throws Exception
{ {
if (Events.ON_AFTER_SIZE.equals(event.getName())) 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) { private void onAfterSize(AfterSizeEvent event) {
int width = event.getWidth(); int width = event.getWidth();
if (width == 0) if (width == 0)
@ -184,13 +196,22 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
} }
this.getChildren().clear(); this.getChildren().clear();
renderChart(width, height); renderChart(width, height);
Events.sendEvent(this, new Event(ON_AFTER_RENDER_CHART_EVENT));
} }
/**
* @return title
*/
public String getTitle() public String getTitle()
{ {
return m_text; return m_text;
} }
/**
* render chart
* @param chartWidth
* @param chartHeight
*/
private void renderChart(int chartWidth, int chartHeight) private void renderChart(int chartWidth, int chartHeight)
{ {
IndicatorModel model = new IndicatorModel(); IndicatorModel model = new IndicatorModel();
@ -207,6 +228,9 @@ public class WPerformanceIndicator extends Panel implements EventListener<Event>
this.getFirstChild().addEventListener(Events.ON_CLICK, this); this.getFirstChild().addEventListener(Events.ON_CLICK, this);
} }
/**
* Class for color map options
*/
public static class Options { public static class Options {
public Map<String, Color> colorMap; public Map<String, Color> colorMap;
} }

View File

@ -14,16 +14,13 @@
package org.adempiere.webui.dashboard; package org.adempiere.webui.dashboard;
import org.adempiere.webui.apps.graph.WPAPanel; 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.apps.graph.WPerformanceIndicator.Options;
import org.adempiere.webui.util.ServerPushTemplate; import org.adempiere.webui.util.ServerPushTemplate;
import org.compiere.model.MGoal; 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.au.out.AuScript;
import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions; 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; import org.zkoss.zk.ui.util.Clients;
/** /**
@ -32,65 +29,51 @@ import org.zkoss.zk.ui.util.Clients;
* @date November 20, 2008 * @date November 20, 2008
*/ */
public class DPPerformance extends DashboardPanel { public class DPPerformance extends DashboardPanel {
private static final String ON_POST_RENDER_ATTR = "onPostRender.Event.Posted";
/** /**
* * generated serial id
*/ */
private static final long serialVersionUID = -8878665031716441912L; private static final long serialVersionUID = -8878665031716441912L;
/** performance chart panel */
private WPAPanel paPanel; private WPAPanel paPanel;
private MGoal[] performanceData; private MGoal[] performanceData;
/**
* Default constructor
*/
public DPPerformance() public DPPerformance()
{ {
super(); super();
setSclass("performance-widget"); 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(); paPanel = new WPAPanel();
appendChild(paPanel); appendChild(paPanel);
paPanel.addEventListener(WPerformanceIndicator.ON_AFTER_RENDER_CHART_EVENT, e -> onPostRender());
} }
@Override
public void refresh(ServerPushTemplate template) { 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) { if (Executions.getCurrent() != null) {
updateUI(); 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);
}
} else { } else {
template.executeAsync(this); template.executeAsync(this);
} }
} }
@Override /**
public void onPageAttached(Page newpage, Page oldpage) { * Adjust {@link #paPanel} height to match chart/content height
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
public void onPostRender() public void onPostRender()
{ {
removeAttribute(ON_POST_RENDER_ATTR);
if (this.getFirstChild() != null) 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(); Component grid = this.getFirstChild().getFirstChild();
String script = "setTimeout(function() { let grid = jq('#" + grid.getUuid() + "');"; 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) if (Executions.getCurrent() != null)
Clients.response(new AuScript(script)); Clients.response(new AuScript(script));
this.getFirstChild().invalidate();
} }
} }