From e479eb5cfb959ad6bd870b765736b6b4dead15a9 Mon Sep 17 00:00:00 2001 From: hengsin Date: Fri, 17 Mar 2023 18:45:56 +0800 Subject: [PATCH] IDEMPIERE-5609 Dashboard Performance Indicators incrementally redrawed on DC drag and drop (#1736) --- .../src/org/compiere/model/MSysConfig.java | 2 + .../adempiere/webui/apps/graph/WPAPanel.java | 68 ++++++++++++++++--- .../apps/graph/WPerformanceIndicator.java | 44 +++++++++--- .../webui/dashboard/DPPerformance.java | 51 +++++--------- 4 files changed, 111 insertions(+), 54 deletions(-) diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index 2cf37cc84e..0522a10cbb 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -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"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java index 77cc4c6c53..c0699f7955 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPAPanel.java @@ -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 { - /** - * + * 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 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 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 grid.appendChild(rows); Row row = null; + List 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 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 } // 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); diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java index 05357b97b5..fb55d01fbe 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/graph/WPerformanceIndicator.java @@ -42,23 +42,29 @@ import org.zkoss.zul.Menupopup; */ public class WPerformanceIndicator extends Panel implements EventListener { + /** + * 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 /** 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 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 } // getGoal /** - * Init Graph Display + * Initialization * Kinamo (pelgrim) */ private void init() @@ -142,10 +148,12 @@ public class WPerformanceIndicator extends Panel implements EventListener 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 } } + /** + * 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 } } 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 this.getFirstChild().addEventListener(Events.ON_CLICK, this); } + /** + * Class for color map options + */ public static class Options { public Map colorMap; } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java index a9c339272e..e23974be4d 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/dashboard/DPPerformance.java @@ -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(); } }