Search code examples
javavaadin10vaadin-charts

How to apply VaadinIcons as marker symbols in Charts for Vaadin Flow?


I have a Vaadin Charts Flow 6 line chart and would like to define some of the VaadinIcons as Marker Symbols.

How can i achieve this?

MarkerSymbol is an interface that is implemented as

  • MarkerSymbolEnum for providing predefined markers such as eg. circle, square, diamond etc.
  • MarkerSymbolUrl for providing the URL to an image that shall be used as a marker
AtomicInteger xValue = new AtomicInteger(0);
List<Double> yValues = new Random( ).doubles(10, -10, 10).boxed( ).collect(Collectors.toList( ));        
List<DataSeriesItem> items = yValues.stream( )
                             .map(yValue -> new DataSeriesItem(xValue.getAndIncrement( ), yValue))
                             .collect(Collectors.toList( )); 

/* Instead of MarkerSymbolEnum or MarkerSymbolUrl, retrieve a VaadinIcon*/
items.forEach(item -> item.getMarker( ).setSymbol(MarkerSymbolEnum.DIAMOND));
items.forEach(item -> item.getMarker( ).setSymbol(new MarkerSymbolUrl("foo/bar.png")));
// new Icon(VaadinIcon.CHEVRON_UP);

DataSeries series = new DataSeries("example");
series.setData(items);

Chart chart = new Chart(ChartType.LINE);
chart.getConfiguration( ).addSeries(series);

I didn't see an opportunity to retrieve the URL of a VaadinIcon or directly setting it.


Solution

  • You might dynamically construct a URL to a VaadinIcon resource as follows:

    String loc = "https://github.com/vaadin/vaadin-icons/blob/master/assets/png/"
    String url = loc + VaadinIcon.CHEVRON_UP.name().toLowerCase().replace('_', '-');
    items.forEach(item -> item.getMarker( ).setSymbol(new MarkerSymbolUrl(url)));
    

    Vaadin also publishes svg VaadinIcon assets on GitHub. Alternatively, you might prefer pointing to a local directory path.

    The logic used to create the url comes from Icon wrapper constructor public Icon(VaadinIcon icon).

    Vaadin doesn't currently (as of July 2019) seem to allow direct use of VaadinIcons as Marker symbols.

    For reference, I've included some details of classes Marker and Icon.

    CLASS MARKER DETAILS

    Class Marker (extends abstract class AbstractConfigurationObject) has member MarkerSymbol which simply implements interface Serializable.

    Class MarkerSymbolUrl implements interface MarkerSymbol and seems to represent a simple getter/setter wrapper class around String url.

    Class MarkerSymbolEnum only implements a static list of enum values, so not relevant.

    CLASS ICON DETAILS

    Class Icon wrapper constructor public Icon(VaadinIcon icon) calls constructor public Icon(String collection, String icon) with the VaadinIcon, which uses Icon superclass Component functionality to call inherited member function Element.setAttribute(...), which stores the calculated VaadinIcon attribute string (I believe this eventually gets written out in the div tag):

    public Icon(VaadinIcon icon) {
        this(ICON_COLLECTION_NAME, icon.name().toLowerCase().replace('_', '-'));
    }
    
    public Icon(String collection, String icon) {
        // iron-icon's icon-attribute uses the format "collection:name",
        // e.g. icon="vaadin:arrow-down"
        getElement().setAttribute(ICON_ATTRIBUTE_NAME, collection + ':' + icon);
    }
    

    Element extends abstract class Node, which implements interface Serializable.

    NEXT STEPS

    Ultimately, this seems to indicate classes Marker/MarkerSymbol and Icon don't share a common superclass (other than Object), so no interoperability.

    For a deeper dive, I'd look at how the various Vaadin components render the UI using the generated markup, but for now it seems using MarkerSymbolUrl and a dynamically calculated URL from the VaadinIcon represents the only straightforward workaround.