Setting up a sparkline chart with a history enabled tag

Title pretty much says it all. How can I set up a Sparkline chart with its data property bound to a tag value that has history enabled (realtime)?

This is the code I have. I'd also appreciate if you can suggest any ideas on how to improve the code.

package com.inductiveautomation.ignition.examples.ce.components.chemicalstoragetank;

import java.awt.*;
import java.util.Objects;

import com.inductiveautomation.factorypmi.application.components.SparklineChart;
import com.inductiveautomation.ignition.common.tags.model.TagManager;
import com.inductiveautomation.ignition.common.tags.model.TagPath;
import com.inductiveautomation.ignition.common.tags.model.event.InvalidListenerException;
import com.inductiveautomation.ignition.common.tags.model.event.TagChangeEvent;
import com.inductiveautomation.ignition.common.tags.model.event.TagChangeListener;
import com.inductiveautomation.ignition.common.tags.paths.parser.TagPathParser;
import com.inductiveautomation.vision.api.client.components.model.AbstractVisionComponent;



public class SparklineChartComponent extends AbstractVisionComponent implements TagChangeListener {

    private SparklineChart chart;

    private String tagPath;
    private TagManager tagManager;
    private TagPath parsedTagPath;

    private double RANGE_HIGH = 100.0;
    private double RANGE_LOW = 0.0;
    private Color LINE_COLOR = new Color(0,0,255);
    private float LINE_WIDTH = 1.5f;
    private double BORDER_INSET = 0.5;

    public SparklineChartComponent() {


        chart = new SparklineChart();

        chart.setRangeHi(RANGE_HIGH);
        chart.setRangeLo(RANGE_LOW);
        chart.setForeground(LINE_COLOR);
        chart.setLineWidth(LINE_WIDTH);
        chart.setBorderInset(BORDER_INSET);
        add(chart);

    }

    public String getTagPath() {
        return this.tagPath;
    }

    public void setTagPath(String newTagPath) {
        String old = this.tagPath;
        this.tagPath = newTagPath;
        if (!Objects.equals(old, newTagPath) && tagPath != null) {
            subscribeToTagValues();
        }
        firePropertyChange("tagPath", old, newTagPath);
    }

    @Override
    protected void onStartup() {
        super.onStartup();
        tagManager = context.getTagManager();
        if (tagPath != null) {
            subscribeToTagValues();
        }
    }

    @Override
    protected void onShutdown() {
        super.onShutdown();
        tagManager.unsubscribeAsync(parsedTagPath, this);
    }

    private void subscribeToTagValues() {
        try {
            parsedTagPath = TagPathParser.parseSafe(this.tagPath);
            tagManager.subscribeAsync(parsedTagPath, this);
        } catch (Exception e) {
            throw new RuntimeException(e);

        }
    }
    

    @Override
    public void tagChanged(TagChangeEvent tagChangeEvent) throws InvalidListenerException {
        
    }
}



I'll push you again to think through why you're doing this. Vision is entirely designed around the user in the designer setting up bindings. A component should just hold data and react to that data changing, not attempt to automatically retrieve data.

That said, if you want to lean on existing facilities as much as possible, it looks like you want to get a QueryManager instance, then register a TagHistoryQuery created with RealtimeTagHistoryQueryParams. That will deliver a Dataset to your IQueryResponseListener every time the polling re-evaluates.

Is there any way I can embed this spark line chart in another component, and expose the sparkline chart's data property to the parent component so that it is available in the vision property editor?

Give your 'parent' component a Dataset property named data in the bean info, and 'forward' the getData/setData calls from the parent component into the inner sparkline.

2 Likes