Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sitemap interpolation parameter for charts #4610

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ Chart:
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')? &
('yAxisDecimalPattern=' yAxisDecimalPattern=(STRING))?);
('yAxisDecimalPattern=' yAxisDecimalPattern=(STRING))? &
('interpolation=' interpolation=(STRING))?);

Webview:
'Webview' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import org.eclipse.xtext.validation.Check
import java.math.BigDecimal
import org.openhab.core.model.sitemap.sitemap.Input
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
import org.openhab.core.model.sitemap.sitemap.Chart

//import org.eclipse.xtext.validation.Check
/**
Expand All @@ -38,6 +39,7 @@ import org.eclipse.xtext.nodemodel.util.NodeModelUtils
class SitemapValidator extends AbstractSitemapValidator {

val ALLOWED_HINTS = #["text", "number", "date", "time", "datetime"]
val ALLOWED_INTERPOLATION = #["linear", "step"]

@Check
def void checkFramesInFrame(Frame frame) {
Expand Down Expand Up @@ -161,4 +163,14 @@ class SitemapValidator extends AbstractSitemapValidator {
SitemapPackage.Literals.INPUT.getEStructuralFeature(SitemapPackage.INPUT__INPUT_HINT))
}
}

@Check
def void checkInterpolationParameter(Chart i) {
if (i.interpolation !== null && !ALLOWED_INTERPOLATION.contains(i.interpolation)) {
val node = NodeModelUtils.getNode(i)
val line = node.getStartLine()
error("Input on item '" + i.item + "' has invalid interpolation '" + i.interpolation + "' at line " + line,
SitemapPackage.Literals.INPUT.getEStructuralFeature(SitemapPackage.CHART__INTERPOLATION))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ public interface ChartProvider {
* @param items The items to display on the chart
* @param groups The groups to display on the chart
* @param dpi The DPI (dots per inch) value, can be <code>null</code>
* @param interpolation The interpolation between two datapoint (<code>linear</code> or <code>step</code>),
* <code>null</code> defaults to <code>linear</code>)
* @param legend Show the legend? If <code>null</code>, the ChartProvider should make his own decision.
* @return BufferedImage object if the chart is rendered correctly,
* otherwise null.
Expand All @@ -62,7 +64,8 @@ public interface ChartProvider {
*/
BufferedImage createChart(@Nullable String service, @Nullable String theme, ZonedDateTime startTime,
ZonedDateTime endTime, int height, int width, @Nullable String items, @Nullable String groups,
@Nullable Integer dpi, @Nullable Boolean legend) throws ItemNotFoundException;
@Nullable Integer dpi, @Nullable String interpolation, @Nullable Boolean legend)
throws ItemNotFoundException;

/**
* Creates a chart object. This sets the initial parameters for the chart
Expand All @@ -82,6 +85,8 @@ BufferedImage createChart(@Nullable String service, @Nullable String theme, Zone
* @param groups The groups to display on the chart
* @param dpi The DPI (dots per inch) value, can be <code>null</code>
* @param yAxisDecimalPattern The format pattern for the y-axis labels
* @param interpolation The interpolation between two datapoint (<code>linear</code> or <code>step</code>),
* <code>null</code> defaults to <code>linear</code>)
* @param legend Show the legend? If <code>null</code>, the ChartProvider should make his own decision.
* @return BufferedImage object if the chart is rendered correctly,
* otherwise null.
Expand All @@ -90,9 +95,10 @@ BufferedImage createChart(@Nullable String service, @Nullable String theme, Zone
*/
default BufferedImage createChart(@Nullable String service, @Nullable String theme, ZonedDateTime startTime,
ZonedDateTime endTime, int height, int width, @Nullable String items, @Nullable String groups,
@Nullable Integer dpi, @Nullable String yAxisDecimalPattern, @Nullable Boolean legend)
throws ItemNotFoundException {
return createChart(service, theme, startTime, endTime, height, width, items, groups, dpi, legend);
@Nullable Integer dpi, @Nullable String yAxisDecimalPattern, @Nullable String interpolation,
@Nullable Boolean legend) throws ItemNotFoundException {
return createChart(service, theme, startTime, endTime, height, width, items, groups, dpi, interpolation,
legend);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) throws Ser
}

String yAxisDecimalPattern = req.getParameter("yAxisDecimalPattern");
String interpolation = req.getParameter("interpolation");

// Read out parameter 'legend'
String legendParam = req.getParameter("legend");
Expand All @@ -305,7 +306,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) throws Ser
try {
BufferedImage chart = provider.createChart(serviceName, req.getParameter("theme"), beginEnd.begin(),
beginEnd.end(), height, width, req.getParameter("items"), req.getParameter("groups"), dpi,
yAxisDecimalPattern, legend);
yAxisDecimalPattern, interpolation, legend);
// Set the content type to that provided by the chart provider
res.setContentType("image/" + provider.getChartType());
try (ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(res.getOutputStream())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ private LegendPosition getLegendPosition() {

private static final int DPI_DEFAULT = 96;

private static final String INTERPOLATION_LINEAR = "linear";
private static final String INTERPOLATION_STEP = "step";

private final Logger logger = LoggerFactory.getLogger(DefaultChartProvider.class);

private final ItemUIRegistry itemUIRegistry;
Expand All @@ -130,20 +133,21 @@ public String getName() {
@Override
public BufferedImage createChart(@Nullable String serviceId, @Nullable String theme, ZonedDateTime startTime,
ZonedDateTime endTime, int height, int width, @Nullable String items, @Nullable String groups,
@Nullable Integer dpiValue, @Nullable Boolean legend)
@Nullable Integer dpiValue, @Nullable String interpolation, @Nullable Boolean legend)
throws ItemNotFoundException, IllegalArgumentException {
return createChart(serviceId, theme, startTime, endTime, height, width, items, groups, dpiValue, null, legend);
return createChart(serviceId, theme, startTime, endTime, height, width, items, groups, dpiValue, null,
interpolation, legend);
}

@Override
public BufferedImage createChart(@Nullable String serviceId, @Nullable String theme, ZonedDateTime startTime,
ZonedDateTime endTime, int height, int width, @Nullable String items, @Nullable String groups,
@Nullable Integer dpiValue, @Nullable String yAxisDecimalPattern, @Nullable Boolean legend)
throws ItemNotFoundException, IllegalArgumentException {
@Nullable Integer dpiValue, @Nullable String yAxisDecimalPattern, @Nullable String interpolation,
@Nullable Boolean legend) throws ItemNotFoundException, IllegalArgumentException {
logger.debug(
"Rendering chart: service: '{}', theme: '{}', startTime: '{}', endTime: '{}', width: '{}', height: '{}', items: '{}', groups: '{}', dpi: '{}', yAxisDecimalPattern: '{}', legend: '{}'",
"Rendering chart: service: '{}', theme: '{}', startTime: '{}', endTime: '{}', width: '{}', height: '{}', items: '{}', groups: '{}', dpi: '{}', yAxisDecimalPattern: '{}', interpolation: '{}', legend: '{}'",
serviceId, theme, startTime, endTime, width, height, items, groups, dpiValue, yAxisDecimalPattern,
legend);
interpolation, legend);

// If a persistence service is specified, find the provider, or use the default provider
PersistenceService service = (serviceId == null) ? persistenceServiceRegistry.getDefault()
Expand Down Expand Up @@ -188,8 +192,8 @@ public BufferedImage createChart(@Nullable String serviceId, @Nullable String th
// axis
styler.setAxisTickLabelsFont(chartTheme.getAxisTickLabelsFont(dpi));
styler.setAxisTickLabelsColor(chartTheme.getAxisTickLabelsColor());
styler.setXAxisMin((double) startTime.toInstant().toEpochMilli());
styler.setXAxisMax((double) endTime.toInstant().toEpochMilli());
styler.setXAxisMin(startTime.toInstant().toEpochMilli());
styler.setXAxisMax(endTime.toInstant().toEpochMilli());
int yAxisSpacing = Math.max(height / 10, chartTheme.getAxisTickLabelsFont(dpi).getSize());
if (yAxisDecimalPattern != null) {
styler.setYAxisDecimalPattern(yAxisDecimalPattern);
Expand Down Expand Up @@ -219,7 +223,7 @@ public BufferedImage createChart(@Nullable String serviceId, @Nullable String th
for (String itemName : itemNames) {
Item item = itemUIRegistry.getItem(itemName);
if (addItem(chart, persistenceService, startTime, endTime, item, seriesCounter, chartTheme, dpi,
legendPositionDecider)) {
interpolation, legendPositionDecider)) {
seriesCounter++;
}
}
Expand All @@ -233,7 +237,7 @@ public BufferedImage createChart(@Nullable String serviceId, @Nullable String th
if (item instanceof GroupItem groupItem) {
for (Item member : groupItem.getMembers()) {
if (addItem(chart, persistenceService, startTime, endTime, member, seriesCounter, chartTheme,
dpi, legendPositionDecider)) {
dpi, interpolation, legendPositionDecider)) {
seriesCounter++;
}
}
Expand Down Expand Up @@ -307,7 +311,7 @@ private double convertData(State state) {

private boolean addItem(XYChart chart, QueryablePersistenceService service, ZonedDateTime timeBegin,
ZonedDateTime timeEnd, Item item, int seriesCounter, ChartTheme chartTheme, int dpi,
LegendPositionDecider legendPositionDecider) {
@Nullable String interpolation, LegendPositionDecider legendPositionDecider) {
Color color = chartTheme.getLineColor(seriesCounter);

// Get the item label
Expand Down Expand Up @@ -358,7 +362,9 @@ private boolean addItem(XYChart chart, QueryablePersistenceService service, Zone
for (HistoricItem historicItem : result) {
// For 'binary' states, we need to replicate the data
// to avoid diagonal lines
if (state instanceof OnOffType || state instanceof OpenClosedType) {
if (state != null && INTERPOLATION_STEP.equals(interpolation)
|| ((state instanceof OnOffType || state instanceof OpenClosedType)
&& !INTERPOLATION_LINEAR.equals(interpolation))) {
xData.add(Date.from(historicItem.getInstant().minus(1, ChronoUnit.MILLIS)));
yData.add(convertData(state));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ protected Sitemap buildSitemap(RootUIComponent rootComponent) {
setWidgetPropertyFromComponentConfig(widget, component, "legend", SitemapPackage.CHART__LEGEND);
setWidgetPropertyFromComponentConfig(widget, component, "forceAsItem",
SitemapPackage.CHART__FORCE_AS_ITEM);
setWidgetPropertyFromComponentConfig(widget, component, "yAxisDecimalPattern",
SitemapPackage.CHART__YAXIS_DECIMAL_PATTERN);
setWidgetPropertyFromComponentConfig(widget, component, "interpolation",
SitemapPackage.CHART__INTERPOLATION);
break;
case "Webview":
WebviewImpl webviewWidget = (WebviewImpl) SitemapFactory.eINSTANCE.createWebview();
Expand Down