package fr.openwide.core.wicket.more.jqplot.data.adapter;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import org.apache.wicket.model.IModel;
import org.apache.wicket.util.convert.IConverter;
import com.google.common.collect.Lists;
import com.google.common.collect.Table;
import fr.openwide.core.commons.util.collections.DateDiscreteDomain;
import fr.openwide.core.commons.util.collections.PartitionDiscreteDomain;
import fr.openwide.core.commons.util.rendering.IRenderer;
import fr.openwide.core.wicket.more.jqplot.config.JQPlotConfigurers;
import fr.openwide.core.wicket.more.jqplot.data.provider.IJQPlotDataProvider;
import fr.openwide.core.wicket.more.jqplot.data.provider.JQPlotMapDataProvider;
import fr.openwide.core.wicket.more.jqplot.data.provider.JQPlotTableDataProvider;
import fr.openwide.core.wicket.more.model.ContiguousSetModel;
import nl.topicus.wqplot.components.plugins.JQPlotCategoryAxisRenderer;
import nl.topicus.wqplot.data.NumberSeries;
import nl.topicus.wqplot.options.PlotOptions;
import nl.topicus.wqplot.options.PlotSeries;
import nl.topicus.wqplot.options.PlotTick;
/**
* Adapter for data with discrete keys.
* <p>This adapter assigns an index to each data point so that all charts (especially bar charts) will render correctly.
* <p>This is only useful if your data references keys from a discrete domain (i.e. with a small, finite number of values
* in a given range). This is the case when your keys are labels ("male"/"female"), but also when they are ranges
* (e.g. the first day of each week at midnight, which represents the whole week).
* <p>If your data keys are only "almost-continuous" keys (such as floating-point numbers, or dates precise
* to the second, use a {@link AbstractJQPlotContinuousKeysDataAdapter} instead.
*
* @see AbstractJQPlotContinuousKeysDataAdapter
* @see ContiguousSetModel
* @see PartitionDiscreteDomain
* @see DateDiscreteDomain
* @see JQPlotConfigurers#xAxisExplicitTicks(IConverter)
*/
public class JQPlotDiscreteKeysDataAdapter<S, K, V extends Number> extends AbstractMissingValuesJQPlotDataAdapter<S, K, V> {
private static final long serialVersionUID = 3961697302069579609L;
private final IRenderer<? super K> keyRenderer;
public JQPlotDiscreteKeysDataAdapter(
IModel<Table<S, K, V>> tableModel,
IModel<? extends Collection<? extends S>> seriesModel,
IModel<? extends Collection<? extends K>> keysModel,
IRenderer<? super K> keyRenderer) {
this(new JQPlotTableDataProvider<>(tableModel), seriesModel, keysModel, keyRenderer);
}
public JQPlotDiscreteKeysDataAdapter(
IModel<Table<S, K, V>> tableModel,
IModel<? extends Collection<? extends S>> seriesModel,
IModel<? extends Collection<? extends K>> keysModel,
IModel<? extends V> missingValueReplacementModel,
IRenderer<? super K> keyRenderer) {
this(new JQPlotTableDataProvider<>(tableModel), seriesModel, keysModel, missingValueReplacementModel, keyRenderer);
}
public JQPlotDiscreteKeysDataAdapter(
IModel<Map<K, V>> mapModel,
IModel<? extends Collection<? extends K>> keysModel,
IRenderer<? super K> keyRenderer) {
this(new JQPlotMapDataProvider<S, K, V>(mapModel), null, keysModel, keyRenderer);
}
public JQPlotDiscreteKeysDataAdapter(
IJQPlotDataProvider<S, K, V> dataProvider,
IModel<? extends Collection<? extends S>> seriesModel,
IModel<? extends Collection<? extends K>> keysModel,
IRenderer<? super K> keyRenderer) {
this(dataProvider, seriesModel, keysModel, null, keyRenderer);
}
public JQPlotDiscreteKeysDataAdapter(
IJQPlotDataProvider<S, K, V> dataProvider,
IModel<? extends Collection<? extends S>> seriesModel,
IModel<? extends Collection<? extends K>> keysModel,
IModel<? extends V> missingValueReplacementModel,
IRenderer<? super K> keyRenderer) {
super(dataProvider, seriesModel, keysModel, missingValueReplacementModel);
this.keyRenderer = keyRenderer;
}
@Override
public void configure(PlotOptions options, Map<? extends S, PlotSeries> seriesMap, Map<? extends K, PlotTick> keysMap, Locale locale) {
options.getAxes().getXaxis()
.setRenderer(JQPlotCategoryAxisRenderer.get());
for (Map.Entry<? extends K, PlotTick> tickEntry : keysMap.entrySet()) {
tickEntry.getValue().setVal(keyRenderer.render(tickEntry.getKey(), locale));
}
}
@Override
public Collection<NumberSeries<Integer, V>> getObject(Locale locale) {
Iterable<? extends K> keysTicks = getKeysTicks();
Collection<NumberSeries<Integer, V>> result = Lists.newArrayList();
for (S series : getSeriesTicks()) {
NumberSeries<Integer, V> seriesData = createSeriesData(series, keysTicks);
result.add(seriesData);
}
return result;
}
private NumberSeries<Integer, V> createSeriesData(S series, Iterable<? extends K> keys) {
NumberSeries<Integer, V> seriesData = new NumberSeries<Integer, V>();
int index = 1; // Categories index starts at 1 for jqPlot
for (K key : keys) {
V value = getValue(series, key);
seriesData.addEntry(index, value);
++index;
}
return seriesData;
}
}