com.databasesandlife.util.wicket.CountingUpThenAutoRefreshingLabel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-common Show documentation
Show all versions of java-common Show documentation
Utility classes developed at Adrian Smith Software (A.S.S.)
package com.databasesandlife.util.wicket;
import org.apache.wicket.ajax.AbstractAjaxTimerBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.LambdaModel;
import org.apache.wicket.model.PropertyModel;
import org.apache.wicket.util.time.Duration;
import java.text.DecimalFormat;
import java.text.NumberFormat;
/**
* A <span> label which firstly counts up towards its model's value, and secondly auto-refreshes that value.
* The component implements similar functionality to "worldwide members" number on the avaaz homepage.
*
* Usage:
*
* <!-- In HTML file -->
* <span wicket:id="numberOfUsers"></span>
*
* // In Java file
* CountingUpThenAutoRefreshingLabel label = new CountingUpThenAutoRefreshingLabel("numberOfUsers");
* label.setDefaultModel(new PropertyModel(dataSource, "userCount")); // model returns Integer
* add(label);
*
*
* The first phase of the component lasts two minutes, and the value counts up from zero to the target value.
* It "tends" towards the target value, i.e. moves fast at the beginning, then slows down as it approaches its target value.
*
*
* The second phase, triggered after the first two minutes, simply refreshes the value periodically from the server.
* Initially this is refreshed every two seconds, but this refresh interval is gradually slowed down,
* so that if N users leave their browsers open for a long time, we will not get N requests every two seconds forever.
*
*
* Various numerical values above may be altered with:
*
* label.setCountingUpDurationSeconds(120);
* label.setCountingUpRefreshIntervalSeconds(0.1);
* label.setTendencyThreshold(0.001);
* label.setAutoRefreshingInitialIntervalSeconds(2.0);
* label.setAutoRefreshingIntervalMultiplier(1.2);
*
* @author This source is copyright Adrian Smith and licensed under the LGPL 3.
* @see Project on GitHub
*/
public class CountingUpThenAutoRefreshingLabel extends Panel {
protected double countingUpDurationSeconds = 5;
protected double countingUpRefreshIntervalSeconds = 0.1;
protected double tendencyThreshold = 0.001;
protected double autoRefreshingIntervalMultiplier = 1.2;
protected Label label, js;
protected AbstractAjaxTimerBehavior currentSelfUpdatingBehavior;
protected double autoRefreshIntervalSeconds = 2.0;
public CountingUpThenAutoRefreshingLabel(String wicketId) {
super(wicketId);
label = new Label("label", LambdaModel.of(this::getLabelValue));
label.setOutputMarkupId(true);
add(label);
currentSelfUpdatingBehavior = new AbstractAjaxTimerBehavior(Duration.seconds(10)) {
protected void onTimer(AjaxRequestTarget target) { autoRefreshCallback(target); };
};
add(currentSelfUpdatingBehavior);
js = new Label("js", LambdaModel.of(this::getJs));
js.setEscapeModelStrings(false);
add(js);
setOutputMarkupId(true);
}
/** How long should the initial phase of counting up be? Measured in seconds */
public void setCountingUpDurationSeconds(double x) { countingUpDurationSeconds = x; }
/** What should the duration between the updates during the counting up phase be? Measured in seconds. Can be less than one. */
public void setCountingUpRefreshIntervalSeconds(double x) { countingUpRefreshIntervalSeconds = x; }
/** How close should the counting up phase get to the target value? A value of 0.01 means it gets within 1% of the target value
* before switching to the second auto-refresh phase. */
public void setTendencyThreshold(double x) { tendencyThreshold = x; }
/** During the auto-refresh phase, what should the duration be between server-refreshes, initially? */
public void setAutoRefreshingInitialIntervalSeconds(double x) { autoRefreshIntervalSeconds = x; }
/** During the auto-refresh phase, by what multiplier should the auto-refresh interval durations increase? For example 2.0
* means they double; so for example the first duration might be 10s, the next 20s, the next 40s, etc. */
public void setAutoRefreshingIntervalMultiplier(double x) { autoRefreshingIntervalMultiplier = x; }
/** INTERNAL METHOD -- DO NOT USE */
public String getLabelValue() {
var f = NumberFormat.getInstance(getLocale());
if (f instanceof DecimalFormat) {
((DecimalFormat) f).setGroupingUsed(true);
}
var val = (Integer) getDefaultModelObject();
return f.format(val);
}
protected String getThousandSeparator() {
var f = NumberFormat.getInstance(getLocale());
if (f instanceof DecimalFormat)
return "" + ((DecimalFormat) f).getDecimalFormatSymbols().getGroupingSeparator();
else
return "";
}
/** INTERNAL METHOD -- DO NOT USE */
public String getJs() {
// CountingUpThenAutoRefreshLabel_continueCounting(",", document.getElementById("labelWICKETID"), 1000, 1000);
var result = "";
result += "var countingUpDurationSeconds = " + countingUpDurationSeconds + ";\n";
result += "var countingUpRefreshIntervalSeconds = " + countingUpRefreshIntervalSeconds + ";\n";
result += "var tendencyThreshold = " + tendencyThreshold + ";\n";
result += "var thousandSeparator = \"" + getThousandSeparator() + "\";\n";
result += "var element = document.getElementById(\"" + label.getMarkupId() + "\");\n";
result += "var targetValue = " + (Integer) getDefaultModelObject() + ";\n";
result += "CountingUpThenAutoRefreshLabel_continueCounting(countingUpDurationSeconds, countingUpRefreshIntervalSeconds, tendencyThreshold, " +
"thousandSeparator, element, targetValue, targetValue);\n";
return result;
}
protected void autoRefreshCallback(AjaxRequestTarget target) {
// Not sure if this works; Eclipse suggested this when upgrading to Wicket 6
currentSelfUpdatingBehavior.stop(target); // remove(..) doesn't seem to work; although I'm worried this could be a memory leak
currentSelfUpdatingBehavior = new AbstractAjaxTimerBehavior(Duration.seconds(autoRefreshIntervalSeconds)) {
protected void onTimer(AjaxRequestTarget target) { autoRefreshCallback(target); };
};
add(currentSelfUpdatingBehavior);
js.setVisible(false);
target.add(this);
autoRefreshIntervalSeconds *= autoRefreshingIntervalMultiplier;
}
}