Using Datasource On Gauge Chart

I’m trying to use a Gauge Chart to report the performance of a KPI using a value collection datasource. Unfortunately, it seems like the same chart with the same vaues is being displayed on all KPI’s that I select.

What am I doing wrong?

This is what I have:

ProjectkpiEdit.xml

<valueCollectionDatasource id="kpiGaugeDs">
            <query>
                <![CDATA[select k.baseline as baseline, k.target as target, k.actual+k.baseline as actuals
from ppm$KPI k]]>
            </query>
            <properties>
                <property datatype="int"
                          name="baseline"/>
                <property datatype="int"
                          name="target"/>
                <property datatype="int"
                          name="actuals"/>
            </properties>
        </valueCollectionDatasource>

<chart:gaugeChart id="gaugeChart"
                                  datasource="kpiGaugeDs"
                                  height="300px">
                    <chart:axes>
                        <chart:axis id="gaugeChartAxis"
                                    axisAlpha="1"
                                    axisColor="BROWN"
                                    axisThickness="3"
                                    bottomTextYOffset="-20"
                                    tickAlpha="0.5"
                                    tickColor="BROWN">
                            <!--   valueInterval="100"-->
                        </chart:axis>
                    </chart:axes>
                    <chart:arrows>
                        <!--chart:arrow color="" -->
                        <chart:arrow/>
                    </chart:arrows>
                    <chart:export/>
                </chart:gaugeChart>'''

ProjectkpiEdit.java;

@public class ProjectkpiEdit extends AbstractEditor<KPI> {

    @Inject
    private CollectionDatasource<KeyValueEntity, Object> kpiGaugeDs;
    @Inject
    private AngularGaugeChart gaugeChart;

    @Override
    protected void postInit() {
        super.postInit();
        kpiGaugeDs.refresh();
        KeyValueEntity value = kpiGaugeDs.getItems().iterator().next();
        Integer startValue = (Integer)value.getValue("baseline");
        Integer endValue = (Integer)value.getValue("target");
        Integer actuals = (Integer)value.getValue("actuals");
        String bottomText = String.valueOf((Integer)value.getValue("actuals"));
        gaugeChart.getAxes().get(0).setStartValue(Double.valueOf(startValue));
        gaugeChart.getAxes().get(0).setEndValue(Double.valueOf(endValue));
        gaugeChart.getAxes().get(0).setBottomText(bottomText+"/"+endValue);
        gaugeChart.getArrows().get(0).setValue(Double.valueOf(actuals)>Double.valueOf(endValue)?Double.valueOf(endValue):Double.valueOf(actuals));
    }'''

kpi.java

    @Column(name = "INDICATOR_")
    protected String indicator;

   @Column(name = "MEASURE")
    protected String measure;

    @Column(name = "WEIGHT")
    protected Integer weight;

    @Column(name = "BASELINE")
    protected Integer baseline;

    @Column(name = "TARGET")
    protected Integer target;

    @Column(name = "BUDGET")
    protected Double budget = 0.0;

    @Column(name = "COST")
    protected Double cost = 0.0;

    @Column(name = "ACTUAL")
    protected Integer actual = 0;'''

What I want to achieve is a gauge that shows the baseline as the startValue, the target as the endValue and the actuals will be shown by the arrow.

image

Hi,

As far as I see, your actual value which is used for an arriow value is bigger than the endValue.

Regards,
Gleb

Hi Gleb,

That is why I have this code…so that the arrow doesn’t do beyond the targetValue

gaugeChart.getArrows().get(0).setValue(
    Double.valueOf(actuals)>Double.valueOf(endValue) ? Double.valueOf(endValue):Double.valueOf(actuals));

What I need most is to understand why when I am creating a new entity, the gauge still has persisted values…Values of the very first KPI I created.

image

It’s hard to guess without a demo project in which the problem is reproduced. I would appreciate if you attach one, so I can investigate the problem.

Hello Gleb,

Give me 30mins I reproduce it on a sample project and I share.

Regards,
Kenince

Hi @gorelov ,

gauge-demo.zip (81.8 KB)

I’ve created a github repo with the sample project and in the process, I’ve discovered a few things:

  1. When creating a new KPI with the java code in the kpiEdit.java, it will throw an error.
    Workaround - comment the code then create a new KPI.

Business Logic behind the KPI is:

  • Baseline is the current value.
  • Target is what we want to achieve
  • Actual is the achievement we’ve made towards meeting the target since we started out the KPI.
  1. Second thing I have discovered is that, the gauge seems to be persisting the values of the newest entry on the KPI list.

Let me know if there’s any more detail I can provide.

Thanks in advance,
Kenince

Hi,

Thank you for the demo project. After a short investigation, I can say that you don’t need a value collection datasource. First of all, you have all the necessary values in the edited item and the second, using a collection datasource, in this case, produces bugs:

  1. It loads only persisted entities and doesn’t know anything about newly created.
  2. Even though you open a persisted entity, you setup a chart corresponding to the first item in the list.

I suggest the following code, which depends on the currently edited entity:

import com.company.gaugedemo.entity.KPI;
import com.google.common.base.MoreObjects;
import com.haulmont.charts.gui.amcharts.model.GaugeArrow;
import com.haulmont.charts.gui.amcharts.model.GaugeAxis;
import com.haulmont.charts.gui.components.charts.AngularGaugeChart;
import com.haulmont.cuba.gui.components.AbstractEditor;
import com.haulmont.cuba.gui.data.Datasource;

import javax.inject.Inject;
import java.util.Map;

public class KPIEdit extends AbstractEditor<KPI> {
    @Inject
    private AngularGaugeChart gaugeChart;
    @Inject
    private Datasource<KPI> kPIDs;

    @Override
    public void init(Map<String, Object> params) {
        // Every time the item property is chaged, update the chart
        kPIDs.addItemPropertyChangeListener(e -> updateChart());
    }

    @Override
    protected void postInit() {
        // Update the chart after screen is opened
        updateChart();
    }

    private void updateChart() {
        KPI item = getItem();
        // Obtain values from the Item. If there are no values for some properties,
        // then the default ones will be set.
        Integer startValue = MoreObjects.firstNonNull(item.getBaseline(), 0);
        Integer endValue = MoreObjects.firstNonNull(item.getTarget(), startValue);
        Integer actual = startValue + MoreObjects.firstNonNull(item.getActual(), 0);
        String bottomText = String.valueOf(actual);

        GaugeAxis gaugeAxis = gaugeChart.getAxes().get(0);
        gaugeAxis.setStartValue(Double.valueOf(startValue));
        gaugeAxis.setEndValue(Double.valueOf(endValue));
        gaugeAxis.setBottomText(bottomText + "/" + endValue);

        GaugeArrow gaugeArrow = gaugeChart.getArrows().get(0);
        gaugeArrow.setValue(Double.valueOf(actual) > Double.valueOf(endValue)
                ? Double.valueOf(endValue)
                : Double.valueOf(actual));

        // Refresh the chart to apply the settings
        gaugeChart.repaint();
    }
}

Regarsd,
Gleb